/**
 @file sys_usw_nexthop_l3.c

 @date 2009-11-23

 @version v2.0

 The file contains all nexthop layer2 related callback function
*/

/****************************************************************************
 *
* Header Files
*
****************************************************************************/
#include "ctc_const.h"
#include "ctc_macro.h"
#include "ctc_error.h"
#include "ctc_linklist.h"
#include "ctc_l3if.h"
#include "ctc_packet.h"

#include "sys_usw_common.h"
#include "sys_usw_port_api.h"
#include "sys_usw_nexthop_api.h"
#include "sys_usw_nexthop_hw.h"
#include "sys_usw_nexthop.h"
#include "sys_usw_vlan.h"
#include "sys_usw_stats_api.h"
#include "sys_usw_qos_api.h"
#include "sys_usw_l3if.h"
#include "sys_usw_register.h"
#include "sys_usw_wb_nh.h"
#include "sys_usw_wb_common.h"

#include "drv_api.h"

extern sys_usw_nh_api_master_t* p_usw_nh_api_master[CTC_MAX_LOCAL_CHIP_NUM_PP];
extern int32
sys_usw_linkagg_get_ports(uint8 lchip, uint8 tid, uint32* p_gports, uint16* cnt);
extern int32
sys_usw_linkagg_get_max_mem_num(uint8 lchip, uint16* max_num);
STATIC int32
_sys_usw_nh_mcast_write_logic_rep(uint8 lchip, sys_nh_info_dsmet_t* dsmet);/*For TMM*/
STATIC int32
_sys_usw_nh_mcast_update_logic_rep_list(uint8 lchip, sys_nh_mcast_meminfo_t* p_member_info, uint32 ref_nhid, uint8 is_add);/*For TMM*/
/****************************************************************************
 *
* Defines and Macros
*
*****************************************************************************/


#define SYS_MC_MAP_PORT_ID(dest_id)  (dest_id&0x3F)
#define SYS_MC_MAP_PBM_PORT_ID(dest_id, port_type, port_id)\
    do{\
      port_type = (dest_id >> 6)&0x3;\
      port_id   = SYS_MC_MAP_PORT_ID(dest_id);\
    }while(0)

#define SYS_MC_DESTID_IS_INTERNAL(port) (((port >= SYS_RSV_PORT_START && port<= SYS_RSV_PORT_END)) && \
    SYS_MC_DESTID_IS_NOT_TOCPU(port))

#define SYS_LOGIC_REP_END_PTR 0x1FFF
/****************************************************************************
 *
* Global and Declaration
*
*****************************************************************************/
extern int32
sys_usw_aps_set_met_entry(uint8 lchip, sys_nh_param_dsmet_t* p_met_info, uint32 basic_met_offset);
/****************************************************************************
 *
* Function
*
*****************************************************************************/

int32
_sys_usw_nh_mcast_write_dsmet(uint8 lchip, sys_nh_info_dsmet_t* p_met_info, sys_nh_param_mcast_member_t* p_mem_param)
{
    sys_met_t dsmet;
    sys_nh_info_mcast_t* p_info_mcast = (sys_nh_info_mcast_t*)p_mem_param->p_info_mcast;
    /*uint8 xgpon_en = 0;*/

    if (p_mem_param->no_hw)
    {
        return CTC_E_NONE;
    }
    sal_memset(&dsmet, 0, sizeof(dsmet));

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "\n\
    lchip = %d\n\
    dsmet_offset = 0x%x, \n\
    dsnh_offset = 0x %x, \n\
    is_linkagg = %d, \n\
    member_type = %d, \n\
    replicate_num = %d, \n\
    ucastid = %d, \n\
    use_pbm = %d,  port_type = %d, pbm0 = 0x%x, pbm1 = 0x%x,\n\
    next_met_offset = 0x %x, \n\
    port_check_discard = %d, \n\
    1st_vlanif = %d\n",
                   lchip,
                   p_met_info->dsmet_offset,
                   p_met_info->dsnh_offset,
                   CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_IS_LINKAGG),
                   p_met_info->member_type,
                   p_met_info->replicate_num,
                   p_met_info->ucastid,
                   CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_USE_PBM), p_met_info->port_type,
                   CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_USE_PBM) ? p_mem_param->pbm_hw[0] : 0,
                   CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_USE_PBM) ? p_mem_param->pbm_hw[1] : 0,
                   p_met_info->next_dsmet_offset,
                   CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD),
                   CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_1ST_VLANIF));

    /*
    dsmet.is_met = 1;
    */

    if (CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_IS_MCAST_APS))
    {
        sys_nh_param_dsmet_t dsmet_para;
        sal_memset(&dsmet_para, 0, sizeof(sys_nh_param_dsmet_t));
        dsmet_para.dest_id = p_met_info->ucastid;
        dsmet_para.met_offset = p_met_info->dsmet_offset;
        dsmet_para.next_met_entry_ptr = p_met_info->next_dsmet_offset;
        dsmet_para.end_local_rep = (CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_ENDLOCAL)?1:0);
        CTC_ERROR_RETURN(sys_usw_aps_set_met_entry(lchip, &dsmet_para, p_info_mcast->basic_met_offset));
        return CTC_E_NONE;
    }

    if (g_usw_nh_master[lchip]->reflective_brg_en)
    {
        CTC_UNSET_FLAG(p_met_info->flag, SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD);
    }

    dsmet.next_hop_ptr   = p_met_info->dsnh_offset;

    if (CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_USE_PBM))
    {
        uint8 i = 0;
        uint32 bmp_valid = 0;
        uint8 bmp_bytes = MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM) >> 3;

        for (i = 0; i < (bmp_bytes >> 2); i++)
        {
            bmp_valid |= p_mem_param->pbm_hw[i]? 1 : 0;
            if (bmp_valid)
            {
                break;
            }
        }
        if (bmp_valid)
        {
            dsmet.mcast_mode  = 1;
            sal_memcpy(dsmet.port_bitmap, p_mem_param->pbm_hw, bmp_bytes);
            dsmet.port_bitmap_base = p_met_info->port_type;
            if (DRV_FROM_AT(lchip))
            {
                if (g_usw_nh_master[lchip]->met_ext_mode)
                {
                    if (p_met_info->port_type >= SYS_MET_VEC_SLIM_2X_0)
                    {
                        dsmet.port_bitmap_base = p_met_info->port_type - SYS_MET_VEC_SLIM_2X_0;
                    }
                    else
                    {
                        dsmet.port_bitmap_base = 0;
                    }
                }
            }
            dsmet.is_agg = CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_IS_LINKAGG);
        }
        else
        {
            dsmet.mcast_mode  = 0;
            dsmet.dest_id  = SYS_NH_MET_DROP_UCAST_ID;
        }

        dsmet.phy_port_chk_discard = CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD);

    }
    else
    {
        dsmet.fid = p_met_info->fid ;
        dsmet.dest_id = p_met_info->ucastid ;
        dsmet.logic_port_check_en = CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_LOGIC_PORT_CHK);

        if (CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_HORIZON_SPLIT_EN))
        {
            dsmet.logic_port_type_check = 1;
        }

        if (CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_REFECTIVE))
        {
            dsmet.force_back_en = 1;
        }



        dsmet.remote_chip = (SYS_NH_PARAM_MCAST_MEM_REMOTE == p_met_info->member_type) ? 1 : 0;
        dsmet.is_destmap_profile = CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_DESTMAP_PROFILE);
        dsmet.is_agg = CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_IS_LINKAGG);
        if (CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_LEAF_CHECK_EN))
        {
            dsmet.leaf_check_en = 1;
        }

        if (CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_LOGIC_PORT_CHK))
        {  /*only apply to vpls/trill/wlan/pbb/overlay*/
            dsmet.logic_dest_port = p_met_info->logic_port;
        }
        else
        {
            dsmet.phy_port_chk_discard = CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD);
        }

        dsmet.aps_bridge_en  = (p_met_info->member_type == SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE) ? 1 : 0;
        dsmet.cloud_sec_en = CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_CLOUD_SEC_EN);
        /*sys_usw_global_get_xgpon_en(lchip, &xgpon_en);
        if (DRV_FROM_TM(lchip) && xgpon_en)
        {
            dsmet.logic_port_check_en = 0;
        }*/
    }

    dsmet.next_met_entry_ptr = p_met_info->next_dsmet_offset;
    dsmet.end_local_rep = CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_ENDLOCAL);
    dsmet.next_hop_ext  = CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_USE_DSNH8W);
    dsmet.replicate_num = p_met_info->replicate_num;
    dsmet.is_12w = (p_met_info->entry_type == SYS_NH_ENTRY_TYPE_MET_12W);
    dsmet.is_6w = ((p_met_info->entry_type == SYS_NH_ENTRY_TYPE_MET_6W)&&(p_met_info->entry_type != SYS_NH_ENTRY_TYPE_MET_12W));

    dsmet.logic_repli_en = CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_EN)?1:0;
    dsmet.vlan_if_en = ((p_met_info->member_type == SYS_NH_PARAM_IPMC_MEM_LOCAL) && p_met_info->vid)?1:0;
    dsmet.lag_l3_mode = CTC_FLAG_ISSET(p_met_info->flag, SYS_NH_DSMET_FLAG_1ST_VLANIF)?1:0;
    dsmet.ldp_ext = p_mem_param->ldp_ext;

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MCAST_MEM, 1);
    CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip, p_met_info->entry_type, p_met_info->dsmet_offset, &dsmet));

    return CTC_E_NONE;
}


STATIC int32
_sys_usw_nh_mcast_write_logic_rep(uint8 lchip, sys_nh_info_dsmet_t* dsmet)/*For TMM*/
{
    uint32 cmd = 0;
    DsQMsgReplicationList_m list;

    sal_memset(&list, 0,sizeof(list));
    SetDsQMsgReplicationList(V, logicalRepHeadPtr_f, &list, dsmet->next_dsmet_offset);
    SetDsQMsgReplicationList(V, nextHopPtrValid_f, &list, 1);
    SetDsQMsgReplicationList(V, nextHopPtr_f, &list, dsmet->dsnh_offset);
    SetDsQMsgReplicationList(V, lastRep_f, &list, dsmet->port_type);

    cmd = DRV_IOW(DsQMsgReplicationList_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, dsmet->dsmet_offset, cmd, &list));
    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_mcast_update_logic_rep_list(uint8 lchip, sys_nh_mcast_meminfo_t* p_member_info, uint32 ref_nhid, uint8 is_add)/*For TMM*/
{
    sys_nh_mcast_meminfo_t* p_logic_rep_node = NULL;
    sys_nh_mcast_meminfo_t* p_mem_flex = NULL;
    ctc_list_pointer_t* p_logic_rep_list = &(p_member_info->dsmet.logic_rep_list);
    uint32 logic_rep_ptr = 0;
    int32 ret = CTC_E_NONE;
    ctc_list_pointer_node_t* p_pos_mem;
    uint8 find_node = 0;
    uint8 port_type = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "dsmet offset:0x%x, mem_nhid:%u \n", p_member_info->dsmet.dsmet_offset, ref_nhid);

    if (is_add)
    {
        sys_nh_info_dsnh_t nh_info;
        sal_memset(&nh_info, 0, sizeof(sys_nh_info_dsnh_t));
        CTC_ERROR_RETURN(_sys_usw_nh_get_nhinfo(lchip, ref_nhid, &nh_info));

        p_logic_rep_node =  mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_mcast_meminfo_t));
        if (NULL == p_logic_rep_node)
        {
            return CTC_E_NO_MEMORY;
        }
        sal_memset(p_logic_rep_node, 0, sizeof(sys_nh_mcast_meminfo_t));
        CTC_ERROR_GOTO(sys_usw_nh_offset_alloc(lchip, SYS_NH_ENTRY_TYPE_LOGIC_REP, 1, &logic_rep_ptr), ret, error0);
        sal_memcpy(&p_logic_rep_node->dsmet, &p_member_info->dsmet, sizeof(sys_nh_info_dsmet_t));

        p_logic_rep_node->dsmet.dsmet_offset = logic_rep_ptr;
        p_logic_rep_node->dsmet.ref_nhid = ref_nhid;
        p_logic_rep_node->dsmet.dsnh_offset = nh_info.dsnh_offset;
        p_logic_rep_node->dsmet.port_type = 1;
        p_logic_rep_node->dsmet.next_dsmet_offset = SYS_LOGIC_REP_END_PTR;

        /* 1. Add new logic replacte member to last*/
        CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_logic_rep(lchip, &p_logic_rep_node->dsmet), ret, error1);

        /* 2. update previous member's next met offset*/
        p_mem_flex = _ctc_container_of(ctc_list_pointer_node_tail(p_logic_rep_list), sys_nh_mcast_meminfo_t, list_head);
        p_mem_flex->dsmet.next_dsmet_offset = logic_rep_ptr;
        CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_logic_rep(lchip, &p_mem_flex->dsmet), ret, error1);
        if (ctc_list_pointer_head(p_logic_rep_list) != (&(p_mem_flex->list_head)))/* at least three member after insert the new member */
        {
            p_mem_flex = _ctc_container_of(p_mem_flex->list_head.p_prev, sys_nh_mcast_meminfo_t, list_head);
            p_mem_flex->dsmet.port_type = 0;
            CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_logic_rep(lchip, &p_mem_flex->dsmet), ret, error1);
        }
        ctc_list_pointer_insert_tail(p_logic_rep_list, &(p_logic_rep_node->list_head));
        p_member_info->dsmet.replicate_num++;

        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MCAST_MEM, 1);
        return CTC_E_NONE;
error1:
        sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_LOGIC_REP, 1, logic_rep_ptr);
error0:
        mem_free(p_logic_rep_node);

        return ret;
    }
    else
    {
        sys_nh_mcast_meminfo_t* p_mem_flex;
        if (p_member_info->dsmet.replicate_num <= SYS_USW_REGISTER_MIN_LOGIC_THRD)
        {
            return CTC_E_INVALID_CONFIG;
        }

        CTC_LIST_POINTER_LOOP(p_pos_mem, p_logic_rep_list)
        {
            p_logic_rep_node = _ctc_container_of(p_pos_mem, sys_nh_mcast_meminfo_t, list_head);
            if (p_logic_rep_node->dsmet.ref_nhid == ref_nhid)
            {
                find_node = 1;
                break;
            }
        }

        if (!find_node)
        {
            return CTC_E_NOT_EXIST;
        }

        logic_rep_ptr = p_logic_rep_node->dsmet.dsmet_offset;
        if (ctc_list_pointer_head(p_logic_rep_list) == (&(p_logic_rep_node->list_head)))/*Target member is first member*/
        {
            if (p_logic_rep_node->list_head.p_next)/*Get next member*/
            {
                /*replace the next to the first*/
                p_mem_flex = _ctc_container_of(p_logic_rep_node->list_head.p_next,sys_nh_mcast_meminfo_t, list_head);
                logic_rep_ptr = p_mem_flex->dsmet.dsmet_offset;/* free the next logic rep ptr*/
                p_mem_flex->dsmet.dsmet_offset = p_logic_rep_node->dsmet.dsmet_offset;
                _sys_usw_nh_mcast_write_logic_rep(lchip, &p_mem_flex->dsmet);
            }
            else/*This is the last member of this group*/
            {
                p_logic_rep_node->dsmet.next_dsmet_offset = SYS_LOGIC_REP_END_PTR;
                p_logic_rep_node->dsmet.dsnh_offset = 0;
                p_mem_flex = p_logic_rep_node;
                _sys_usw_nh_mcast_write_logic_rep(lchip, &p_mem_flex->dsmet);
            }
        }
        else
        {
            p_mem_flex = _ctc_container_of(p_logic_rep_node->list_head.p_prev, sys_nh_mcast_meminfo_t, list_head);
            p_mem_flex->dsmet.next_dsmet_offset = p_logic_rep_node->dsmet.next_dsmet_offset;
            port_type = p_mem_flex->dsmet.port_type;
            /*target member is 2nd last, and pre is 3rd last */
            if ((0 == p_mem_flex->dsmet.port_type) && (1 == p_logic_rep_node->dsmet.port_type))
            {
                /*Set pre member last flag*/
                p_mem_flex->dsmet.port_type = 1;
            }
            _sys_usw_nh_mcast_write_logic_rep(lchip, &p_mem_flex->dsmet);

            /*target member is last, and pre member is 2nd last */
            if ((1 == port_type) && (1 ==  p_logic_rep_node->dsmet.port_type))
            {
                if (ctc_list_pointer_head(p_logic_rep_list) != (&(p_mem_flex->list_head)))
                {
                    /*update 3nd last member*/
                    p_mem_flex = _ctc_container_of(p_mem_flex->list_head.p_prev, sys_nh_mcast_meminfo_t, list_head);
                    p_mem_flex->dsmet.port_type = 1;
                    _sys_usw_nh_mcast_write_logic_rep(lchip, &p_mem_flex->dsmet);
                }
            }
        }
        sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_LOGIC_REP, 1, logic_rep_ptr);
        ctc_list_pointer_delete(p_logic_rep_list, &(p_logic_rep_node->list_head));
        mem_free(p_logic_rep_node);
        p_member_info->dsmet.replicate_num--;
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MCAST_MEM, 1);
    }

    return ret;
}


STATIC int32
_sys_usw_nh_mcast_rep_logic2phy(uint8 lchip, sys_nh_info_mcast_t* p_info_mcast, sys_nh_mcast_meminfo_t* p_member_info, uint32 ref_nhid, uint32 cnt)
{
    int32 ret = 0;
    uint32 index = 0;
    uint32 new_met_offset = 0;
    sys_nh_mcast_meminfo_t* p_logic_node = NULL;
    sys_nh_mcast_meminfo_t* p_mem_pre = NULL;
    sys_nh_mcast_meminfo_t* logic_rep_node = NULL;
    ctc_list_pointer_node_t* p_pos, * p_pos_next;
    ctc_list_pointer_t* p_logic_rep_list = &(p_member_info->dsmet.logic_rep_list);
    uint32 alloc_index = 0;
    sys_nh_mcast_meminfo_t* p_new_mem_info = NULL;
    sys_nh_mcast_meminfo_t* p_last_node = NULL;
    ctc_list_pointer_t temp_list;
    uint8  first_free = 0;
    sys_nh_param_mcast_member_t mem_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "dsmet offset:0x%x, cnt:%u \n", p_member_info->dsmet.dsmet_offset, cnt);
    sal_memset(&mem_param, 0, sizeof(sys_nh_param_mcast_member_t));
    mem_param.p_info_mcast = p_info_mcast;
    if (cnt == 2)
    {
        CTC_LIST_POINTER_LOOP(p_pos, p_logic_rep_list)
        {
            p_logic_node = _ctc_container_of(p_pos, sys_nh_mcast_meminfo_t, list_head);
            if (p_logic_node->dsmet.ref_nhid != ref_nhid)
            {
                break;
            }
        }

        /*logic rep list have 2 member, just need 1 phy met, do replace, do not need alloc new dsmet resource*/
        p_member_info->dsmet.replicate_num = 0;
        p_member_info->dsmet.dsnh_offset = p_logic_node->dsmet.dsnh_offset;
        p_member_info->dsmet.port_type = 0;
        p_member_info->dsmet.ref_nhid = p_logic_node->dsmet.ref_nhid;
        CTC_UNSET_FLAG(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_EN);
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_write_dsmet(lchip, &p_member_info->dsmet, &mem_param));

        CTC_LIST_POINTER_LOOP_DEL(p_pos, p_pos_next, &p_member_info->dsmet.logic_rep_list)
        {
            logic_rep_node = _ctc_container_of(p_pos, sys_nh_mcast_meminfo_t, list_head);
            sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_LOGIC_REP, 1, logic_rep_node->dsmet.dsmet_offset);
            /*delete node from logic replicate list*/
            ctc_list_pointer_delete(&p_member_info->dsmet.logic_rep_list, &(logic_rep_node->list_head));
            mem_free(logic_rep_node);
        }

        goto done;
    }

    /*2. build physical met list*/
    sal_memset(&temp_list, 0, sizeof(temp_list));
    ctc_list_pointer_init(&temp_list);
    p_pos = ctc_list_pointer_head(p_logic_rep_list);
    for (index = 0; index < cnt; index++)
    {
        p_logic_node = _ctc_container_of(p_pos, sys_nh_mcast_meminfo_t, list_head);
        if (p_logic_node->dsmet.ref_nhid == ref_nhid)
        {
            /*need delete member, no need to build in physical list*/
            p_pos = ctc_list_pointer_next(p_pos);
            continue;
        }

        p_new_mem_info = mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_mcast_meminfo_t));
        if (!p_new_mem_info)
        {
            return CTC_E_NO_MEMORY;
        }
        sal_memset(p_new_mem_info,0,sizeof(sys_nh_mcast_meminfo_t));
        sal_memcpy(&p_new_mem_info->dsmet, &p_logic_node->dsmet, sizeof(p_logic_node->dsmet));
        new_met_offset = 0;
        CTC_ERROR_GOTO(sys_usw_nh_offset_alloc(lchip, p_new_mem_info->dsmet.entry_type, 1, &new_met_offset), ret,error0);
        alloc_index++;
        CTC_UNSET_FLAG(p_new_mem_info->dsmet.flag, SYS_NH_DSMET_FLAG_ENDLOCAL);
        CTC_UNSET_FLAG(p_new_mem_info->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_EN);
        p_new_mem_info->dsmet.dsnh_offset = p_logic_node->dsmet.dsnh_offset;
        p_new_mem_info->dsmet.dsmet_offset = new_met_offset;
        p_new_mem_info->dsmet.next_dsmet_offset = SYS_NH_MET_END_REPLICATE_OFFSET;
        p_new_mem_info->dsmet.replicate_num = 0;
        p_new_mem_info->dsmet.port_type = 0;
        CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip, &p_new_mem_info->dsmet, &mem_param), ret,error0);
        if (alloc_index > 1)
        {
            p_last_node->dsmet.next_dsmet_offset = new_met_offset;
            CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip, &p_last_node->dsmet, &mem_param), ret,error0);
        }
        p_last_node = p_new_mem_info;
        p_pos = ctc_list_pointer_next(p_pos);

        /*build temp list*/
        if (alloc_index == 1)
        {
            ctc_list_pointer_insert_head(&temp_list, &(p_new_mem_info->list_head));
        }
        else
        {
            ctc_list_pointer_insert_tail(&temp_list, &(p_new_mem_info->list_head));
        }
    }

    if ((alloc_index + p_info_mcast->physical_replication_num) >= SYS_NH_PHY_REP_MAX_NUM)
    {
        ret = CTC_E_NO_RESOURCE;
        goto error1;
    }

    if (p_last_node == NULL)
    {
        return CTC_E_NONE;
    }
    /*3. switch logic replicate to physical replicate*/
    /*3.1 physical met list last member point to logic met next member*/
    p_last_node->dsmet.dsmet_offset = new_met_offset;
    p_last_node->dsmet.next_dsmet_offset = p_member_info->dsmet.next_dsmet_offset;
    if (!p_member_info->list_head.p_next)
    {
        CTC_SET_FLAG(p_last_node->dsmet.flag, SYS_NH_DSMET_FLAG_ENDLOCAL);      /*last member*/
    }
    else
    {
        CTC_UNSET_FLAG(p_last_node->dsmet.flag, SYS_NH_DSMET_FLAG_ENDLOCAL);
    }
    CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip,  &p_last_node->dsmet, &mem_param), ret,error1);

    /*3.2 logic met pre member point to physical met*/
    p_new_mem_info = _ctc_container_of((temp_list.head.p_next), sys_nh_mcast_meminfo_t, list_head);
    new_met_offset = p_new_mem_info->dsmet.dsmet_offset;
    if (ctc_list_pointer_head(&p_info_mcast->p_mem_list) == (&(p_member_info->list_head)))
    {
        p_mem_pre =  _ctc_container_of(p_new_mem_info->list_head.p_next, sys_nh_mcast_meminfo_t, list_head);
        p_new_mem_info->dsmet.dsmet_offset = p_member_info->dsmet.dsmet_offset;
        if (p_mem_pre)
        {
            p_new_mem_info->dsmet.next_dsmet_offset = p_mem_pre->dsmet.dsmet_offset;
            CTC_UNSET_FLAG(p_new_mem_info->dsmet.flag, SYS_NH_DSMET_FLAG_ENDLOCAL);
        }
        else
        {
            p_new_mem_info->dsmet.next_dsmet_offset = p_member_info->dsmet.next_dsmet_offset;
        }
        CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip,  &p_new_mem_info->dsmet, &mem_param), ret,error1);
        sys_usw_nh_offset_free(lchip, p_new_mem_info->dsmet.entry_type, 1, new_met_offset);
        first_free = 1;
    }
    else
    {
        p_mem_pre =  _ctc_container_of(p_member_info->list_head.p_prev, sys_nh_mcast_meminfo_t, list_head);
        p_mem_pre->dsmet.next_dsmet_offset = p_new_mem_info->dsmet.dsmet_offset;
        CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip,  &p_mem_pre->dsmet, &mem_param), ret,error1);
    }

    /*4. add new node db*/
    if (ctc_list_pointer_head(&p_info_mcast->p_mem_list) == (&(p_member_info->list_head)))  /*1st node*/
    {
        p_info_mcast->p_mem_list.head.p_next = temp_list.head.p_next;
        p_info_mcast->p_mem_list.head.p_prev = temp_list.head.p_prev;
        temp_list.head.p_next->p_prev = &(p_info_mcast->p_mem_list.head);
    }
    else
    {
        p_mem_pre = _ctc_container_of(p_member_info->list_head.p_prev, sys_nh_mcast_meminfo_t, list_head);
        p_mem_pre->list_head.p_next = (temp_list.head.p_next);
        (temp_list.head.p_next)->p_prev = &p_mem_pre->list_head;
    }
    p_last_node->list_head.p_next = &(p_member_info->list_head);
    p_member_info->list_head.p_prev = &(p_last_node->list_head);

    /*5. free logic replicate resource */
    CTC_LIST_POINTER_LOOP_DEL(p_pos, p_pos_next, &p_member_info->dsmet.logic_rep_list)
    {
        logic_rep_node = _ctc_container_of(p_pos, sys_nh_mcast_meminfo_t, list_head);
        sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_LOGIC_REP, 1, logic_rep_node->dsmet.dsmet_offset);
        /*delete node from logic replicate list*/
        ctc_list_pointer_delete(&p_member_info->dsmet.logic_rep_list, &(logic_rep_node->list_head));
        mem_free(logic_rep_node);
    }
    /*remove logic replicate dsmet member from mcast group*/
    ctc_list_pointer_delete(&p_info_mcast->p_mem_list, &(p_member_info->list_head));
    if (!first_free)
    {
        sys_usw_nh_offset_free(lchip, p_member_info->dsmet.entry_type, 1, p_member_info->dsmet.dsmet_offset);
    }
    mem_free(p_member_info);

    p_info_mcast->p_mem_list.count += (cnt-1);
    p_info_mcast->physical_replication_num += (cnt-2);

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "dsmet list cnt:%u \n", p_info_mcast->p_mem_list.count);
done:
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_INFO_MCAST, 1);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MCAST_MEM, 1);

    return CTC_E_NONE;
    error0:
    if (new_met_offset)
    {
        sys_usw_nh_offset_free(lchip, p_new_mem_info->dsmet.entry_type, 1, new_met_offset);
    }
    mem_free(p_new_mem_info);

    error1:
    p_last_node = _ctc_container_of((temp_list.head.p_next), sys_nh_mcast_meminfo_t, list_head);
    for (index = 0; index < alloc_index; index++)
    {
        p_new_mem_info = p_last_node;
        sys_usw_nh_offset_free(lchip, p_new_mem_info->dsmet.entry_type, 1, p_new_mem_info->dsmet.dsmet_offset);
        if (p_new_mem_info->list_head.p_next)
        {
            p_last_node = _ctc_container_of(p_new_mem_info->list_head.p_next, sys_nh_mcast_meminfo_t, list_head);
        }
        mem_free(p_new_mem_info);
    }
    return ret;
}

STATIC int32
_sys_usw_nh_mcast_rep_phy2logic(uint8 lchip, sys_nh_info_mcast_t* p_info_mcast, sys_nh_mcast_meminfo_t* p_first_node,
                sys_nh_mcast_meminfo_t* p_cur_member, uint32 cnt)
{
    int32 ret = 0;
    uint32 logic_rep_ptr = 0;
    uint32 index = 0;
    sys_nh_mcast_meminfo_t* p_mem_flex = p_first_node;
    uint32 new_met_offset = 0;
    sys_nh_mcast_meminfo_t* p_new_mem_info = NULL;
    sys_nh_mcast_meminfo_t* p_mem_pre = NULL;
    sys_nh_mcast_meminfo_t* p_mem_last = NULL;
    sys_nh_mcast_meminfo_t* p_mem = NULL;
    uint8  alloc_met_flag = 0;
    sys_nh_mcast_meminfo_t* p_rep_node = NULL;
    uint8  is_1st_node = 0;
    ctc_list_pointer_node_t* p_pos, * p_pos_next;
    sys_nh_param_mcast_member_t mem_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "dsmet offset:0x%x, cnt:%u \n", p_first_node->dsmet.dsmet_offset, cnt);
    sal_memset(&mem_param, 0, sizeof(sys_nh_param_mcast_member_t));
    mem_param.p_info_mcast = p_info_mcast;

    p_new_mem_info = mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_mcast_meminfo_t));
    if (!p_new_mem_info)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_new_mem_info, 0, sizeof(sys_nh_mcast_meminfo_t));
    sal_memcpy(&p_new_mem_info->dsmet, &p_first_node->dsmet, sizeof(sys_nh_info_dsmet_t));

    /*1. alloc new dsmet use logic replicate list */
    CTC_ERROR_GOTO(sys_usw_nh_offset_alloc(lchip, p_first_node->dsmet.entry_type, 1, &new_met_offset), ret, error0);
    alloc_met_flag = 1;

    /*2. Prepare mcast logic replicate list*/
    CTC_ERROR_GOTO(sys_usw_nh_offset_alloc(lchip, SYS_NH_ENTRY_TYPE_LOGIC_REP, cnt, &logic_rep_ptr), ret, error1);
    CTC_SET_FLAG(p_new_mem_info->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_EN);
    CTC_UNSET_FLAG(p_new_mem_info->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_PORT_CHK);
    ctc_list_pointer_init(&(p_new_mem_info->dsmet.logic_rep_list));
    p_new_mem_info->dsmet.dsmet_offset = new_met_offset;
    p_new_mem_info->dsmet.dsnh_offset = logic_rep_ptr;
    CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip,  &p_new_mem_info->dsmet, &mem_param), ret,error2);
    p_mem_flex = p_first_node;
    p_mem_last = p_first_node;
    for (index = 0; index < cnt; index++)
    {
        p_rep_node = mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_mcast_meminfo_t));
        if (!p_rep_node)
        {
            ret = CTC_E_NO_MEMORY;
            goto error2;
        }
        sal_memset(p_rep_node,0,sizeof(sys_nh_mcast_meminfo_t));
        if (index == cnt-1)
        {
            p_mem_flex = p_cur_member;
        }
        else
        {
            /*last member donot contain new add member*/
            p_mem_last = p_mem_flex;
        }
        sal_memcpy(&p_rep_node->dsmet, &p_mem_flex->dsmet, sizeof(p_rep_node->dsmet));
        p_rep_node->dsmet.port_type = ((index == (cnt-2)) || (index == (cnt-1)))?1:0;
        p_rep_node->dsmet.dsmet_offset = logic_rep_ptr + index;
        p_rep_node->dsmet.next_dsmet_offset = logic_rep_ptr + index + 1;
        CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_logic_rep(lchip, &p_rep_node->dsmet),ret,error2);
        if (p_mem_flex->list_head.p_next)
        {
            p_mem_flex = _ctc_container_of(p_mem_flex->list_head.p_next, sys_nh_mcast_meminfo_t, list_head);
        }
        ctc_list_pointer_insert_tail(&p_new_mem_info->dsmet.logic_rep_list, &(p_rep_node->list_head));
    }

    /*3. switch physical replicate to logic replicate */
    /*3.1 logic rep met point to physical rep list next met*/
    p_new_mem_info->dsmet.next_dsmet_offset = p_mem_last->dsmet.next_dsmet_offset;
    if (!p_mem_last->list_head.p_next)
    {
        CTC_SET_FLAG(p_new_mem_info->dsmet.flag, SYS_NH_DSMET_FLAG_ENDLOCAL);
    }
    CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip, &p_new_mem_info->dsmet, &mem_param), ret,error2);

    /*3.2 physical rep list pre met point to logic rep met*/
    if (ctc_list_pointer_head(&p_info_mcast->p_mem_list) != (&(p_first_node->list_head)))
    {
        p_mem_pre = _ctc_container_of(p_first_node->list_head.p_prev, sys_nh_mcast_meminfo_t, list_head);
        p_mem_pre->dsmet.next_dsmet_offset = new_met_offset;
        CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip, &p_mem_pre->dsmet, &mem_param), ret,error2);
    }
    else
    {
        p_new_mem_info->dsmet.dsmet_offset = p_first_node->dsmet.dsmet_offset;
        CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip, &p_new_mem_info->dsmet, &mem_param), ret,error2);
        sys_usw_nh_offset_free(lchip, p_new_mem_info->dsmet.entry_type, 1, new_met_offset);
        alloc_met_flag = 0;
    }

    /*4. Add new node to db*/
    if (p_mem_last->list_head.p_next)
    {
        ctc_list_pointer_insert_before(&p_info_mcast->p_mem_list, p_mem_last->list_head.p_next, &(p_new_mem_info->list_head));
    }
    else
    {
        ctc_list_pointer_insert_tail(&p_info_mcast->p_mem_list, &(p_new_mem_info->list_head));
    }

    /*5. free physical replicate resource */
    p_mem_flex = p_first_node;
    is_1st_node = (ctc_list_pointer_head(&p_info_mcast->p_mem_list) == (&(p_mem_flex->list_head)))?1:0;
    for (index = 0; index < cnt-1; index++)
    {
        p_mem = _ctc_container_of(p_mem_flex->list_head.p_next, sys_nh_mcast_meminfo_t, list_head);
        if (!is_1st_node || (index != 0))
        {
            sys_usw_nh_offset_free(lchip, p_mem_flex->dsmet.entry_type, 1, p_mem_flex->dsmet.dsmet_offset);
            ctc_list_pointer_delete(&p_info_mcast->p_mem_list, &(p_mem_flex->list_head));
            mem_free(p_mem_flex);
        }

        p_mem_flex = p_mem;
    }
    if (is_1st_node)
    {
        ctc_list_pointer_delete_head(&p_info_mcast->p_mem_list);
        mem_free(p_first_node);
    }

    p_new_mem_info->dsmet.replicate_num = cnt;
    p_info_mcast->physical_replication_num -= (cnt-2);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_INFO_MCAST, 1);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MCAST_MEM, 1);

    return CTC_E_NONE;
    error2:

    CTC_LIST_POINTER_LOOP_DEL(p_pos, p_pos_next, &p_new_mem_info->dsmet.logic_rep_list)
    {
        p_rep_node = _ctc_container_of(p_pos, sys_nh_mcast_meminfo_t, list_head);
        sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_LOGIC_REP, 1, p_rep_node->dsmet.dsmet_offset);
        /*delete node from logic replicate list*/
        ctc_list_pointer_delete(&p_new_mem_info->dsmet.logic_rep_list, &(p_rep_node->list_head));
        mem_free(p_rep_node);
    }
    error1:
    if (alloc_met_flag)
    {
        sys_usw_nh_offset_free(lchip, p_new_mem_info->dsmet.entry_type, 1, new_met_offset);
    }
    error0:
    mem_free(p_new_mem_info);
    return ret;
}

STATIC int32
_sys_usw_nh_mcast_get_l3if_nh_offset(uint8 lchip,
                                     sys_nh_param_mcast_member_t * p_mem_param,
                                     uint32* p_dsnh_offset)
{
    sys_l3if_prop_t l3if_prop;

    if (p_mem_param->is_linkagg)
    {
        l3if_prop.gport = CTC_MAP_TID_TO_GPORT(p_mem_param->destid);
    }
    else
    {
        uint8 gchip = 0;
        uint16 sys_lport = 0;
        CTC_ERROR_RETURN(sys_usw_get_gchip_id(lchip, &gchip));
        sys_lport = SYS_MAP_DRV_LPORT_TO_SYS_LPORT(p_mem_param->destid);
        l3if_prop.gport = CTC_MAP_LPORT_TO_GPORT(gchip, sys_lport);
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "L3if -> destid:0x%x, lport=%d, Gport:0x%x\n",
                       p_mem_param->destid, sys_lport, l3if_prop.gport);

    }

    l3if_prop.l3if_type = p_mem_param->l3if_type;
    l3if_prop.vlan_id = p_mem_param->vid & 0xFFF;
    l3if_prop.cvlan_id = p_mem_param->cvid & 0xFFF;
    if (SYS_NH_PARAM_IPMC_MEM_LOOP_BACK == p_mem_param->member_type)
    {
        l3if_prop.l3if_id = MCHIP_CAP(SYS_CAP_L3IF_RSV_L3IF_ID);
    }
    else
    {
        CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_info(lchip, 0, &l3if_prop));
    }
    CTC_ERROR_RETURN(sys_usw_nh_get_ipmc_dsnh_offset(lchip, l3if_prop.l3if_id, p_mem_param->logic_port, p_mem_param->mtu_no_chk, p_dsnh_offset));


     return CTC_E_NONE;
}


STATIC int32
_sys_usw_nh_mcast_get_port_reflect(uint8 lchip, sys_nh_param_mcast_member_t* p_member)
{
    uint32 port_reflect_bmp[16];
    uint16 lport = 0;
    uint8 gchip = 0;
    uint32* p_gports = NULL;
    uint16 cnt  = 0;
    uint16 i = 0;
    uint16 max_num = 0;
    int32 ret = 0;
    uint32 cmd = 0;

    CTC_ERROR_RETURN(sys_usw_port_api_get_port_reflective(lchip, port_reflect_bmp));
    if (!p_member->is_linkagg)
    {
        uint32 arp_destmap = 0;
        CTC_ERROR_RETURN(sys_usw_get_gchip_id(lchip, &gchip));
        if (!p_member->is_destmap_profile)
        {
            lport  = p_member->destid;
        }
        else
        {
            cmd = DRV_IOR(DsDestMapProfileUc_t, DsDestMapProfileUc_destMap_f);
            DRV_IOCTL(lchip, p_member->destid&0x7FF, cmd, &arp_destmap);
            if (arp_destmap != 0xffff)
            {
                lport = arp_destmap&0xFF;
            }
        }

        if (CTC_BMP_ISSET(port_reflect_bmp, lport))/*p_member.is_src_port_check_dis will be set, if set from nexthop API or set reflect on the port*/
        {
            p_member->is_src_port_check_dis = 1;
        }
    }
    else
    {
        sys_usw_linkagg_get_max_mem_num(lchip, &max_num);
        p_gports = (uint32*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(uint32)*max_num);
        if (NULL == p_gports)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
            return CTC_E_NO_MEMORY;

        }
        sys_usw_linkagg_get_ports(lchip, p_member->destid, p_gports, &cnt);
        for (i = 0; i < cnt; i++)
        {
            gchip = CTC_MAP_GPORT_TO_GCHIP(p_gports[i]);
            if (FALSE == sys_usw_chip_is_local(lchip, gchip))
            {
                continue;
            }
            if (CTC_BMP_ISSET(port_reflect_bmp, CTC_MAP_GPORT_TO_LPORT(p_gports[i])))/*p_member.is_src_port_check_dis will be set, if set from nexthop API or set reflect on the port*/
            {
                p_member->is_src_port_check_dis = 1;
                break;
            }
        }
        mem_free(p_gports);
    }
    if((SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH == p_member->member_type) && sys_usw_nh_is_cpu_nhid(lchip, p_member->ref_nhid))
    {
        p_member->is_src_port_check_dis = 1;
    }
    return ret;
}

STATIC int32
_sys_usw_nh_mcast_analyze_member(uint8 lchip, ctc_list_pointer_t* p_db_member_list,
                                       sys_nh_param_mcast_member_t* p_member,
                                       sys_nh_mcast_meminfo_t** pp_mem_node,
                                       bool* p_entry_exit,
                                       uint32* p_repli_pos)
{

    sys_nh_mcast_meminfo_t* p_meminfo;
    ctc_list_pointer_node_t* p_pos_mem;
    uint8 index = 0;
    uint8 port_type = 0;
    uint16 port_id = 0;
    uint16 hw_ldp_ext = 0;
    uint8 refect_en = 0;
    uint8 xgpon_en = 0;
    uint8 is_match_bitmap = 0;
    ctc_list_pointer_node_t* p_logic_node;
    sys_nh_mcast_meminfo_t* p_logic_rep_node;

    *pp_mem_node = NULL;
    *p_entry_exit = FALSE;
    *p_repli_pos = 0;
    if ((p_member->member_type != SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH) &&
        (p_member->member_type != SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE)
        && (0 == p_member->logic_port))
    {
        p_member->is_logic_port = 0;
    }

    refect_en = (g_usw_nh_master[lchip]->reflective_brg_en || p_member->is_src_port_check_dis);
    CTC_LIST_POINTER_LOOP(p_pos_mem, p_db_member_list)
    {
        p_meminfo = _ctc_container_of(p_pos_mem, sys_nh_mcast_meminfo_t, list_head);
        if (DRV_FROM_TMM(lchip) && p_member->is_ipmc_member && !p_member->is_linkagg && (p_member->p_1st_node_vlanif == NULL))
        {
            if ((p_member->member_type == SYS_NH_PARAM_IPMC_MEM_LOCAL) && (p_member->l3if_type == CTC_L3IF_TYPE_VLAN_IF)
                && (p_meminfo->dsmet.member_type == SYS_NH_PARAM_IPMC_MEM_LOCAL))
            {
                if (CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM)
                    && (p_member->l3if_type == CTC_L3IF_TYPE_VLAN_IF)
                && (p_meminfo->dsmet.vid == p_member->vid)
                && CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) == p_member->is_linkagg
                && (p_member->leaf_check_en == CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_LEAF_CHECK_EN)))
                {
                    p_member->p_1st_node_vlanif = p_meminfo;
                }
            }
            else if ((p_member->member_type == SYS_NH_PARAM_BRGMC_MEM_LOCAL)
                   &&(p_meminfo->dsmet.member_type == SYS_NH_PARAM_BRGMC_MEM_LOCAL))
            {
                if ((!p_member->is_logic_port || sys_usw_nh_is_xgpon_hybrid(lchip, p_member->logic_port)) && CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM)
                    && (CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) == p_member->is_linkagg)
                && (SYS_MC_DESTID_IS_NOT_TOCPU(p_member->destid))
                && (refect_en == !CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD)))
                {
                    p_member->p_1st_node_vlanif = p_meminfo;
                }
            }
        }
        else if (((p_member->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH) || (p_member->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID)) &&
            p_member->logic_rep_ability)
        {
            if (CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_EN))
            {
                if ((p_meminfo->dsmet.ucastid == p_member->destid) &&  (CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) == p_member->is_linkagg) &&
                    (p_meminfo->dsmet.fid == p_member->fid))
                {
                    *pp_mem_node = p_meminfo;
                }

                CTC_LIST_POINTER_LOOP(p_logic_node, &p_meminfo->dsmet.logic_rep_list)
                {
                    p_logic_rep_node = _ctc_container_of(p_logic_node, sys_nh_mcast_meminfo_t, list_head);
                    if (p_logic_rep_node->dsmet.ref_nhid == p_member->ref_nhid)
                    {
                        *pp_mem_node = p_meminfo;
                        *p_entry_exit = TRUE;
                         p_member->ref_list_cnt = p_meminfo->dsmet.replicate_num;
                         return CTC_E_NONE;
                    }
                }
             }
             else
             {
                 if((p_meminfo->dsmet.ref_nhid != p_member->ref_nhid) && (p_meminfo->dsmet.ucastid == p_member->destid) &&
                 (CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) == p_member->is_linkagg) &&
                 (p_meminfo->dsmet.fid == p_member->fid) && CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_ABILITY))
                 {
                     if (p_member->p_1st_node == NULL)
                     {
                         p_member->p_1st_node = p_meminfo;
                     }
                     p_member->p_last_node = p_meminfo;
                     p_member->ref_list_cnt++;
                 }
             }
         }
        if (p_meminfo->dsmet.member_type != p_member->member_type)
        {
            if((((SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE == p_meminfo->dsmet.member_type)||(SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE == p_member->member_type))
                &&(p_meminfo->dsmet.ref_nhid == p_member->ref_nhid))  || ((SYS_NH_PARAM_BRGMC_MEM_LOCAL == p_meminfo->dsmet.member_type ||
                SYS_NH_PARAM_BRGMC_MEM_BITMAP ==  p_meminfo->dsmet.member_type) && (SYS_NH_PARAM_BRGMC_MEM_LOCAL == p_member->member_type ||
                SYS_NH_PARAM_BRGMC_MEM_BITMAP ==  p_member->member_type)&& p_member->is_del))
            {

            }
            else
            {
                continue;
            }
        }

        hw_ldp_ext = 0;
        if (CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM) ||
            CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_LDP_EXT_EN))
        {
            if (p_member->no_hw)
            {
                sys_nh_mcast_meminfo_param_t* mem_param = (sys_nh_mcast_meminfo_param_t*)p_meminfo;
                sal_memcpy(p_member->pbm_hw, mem_param->member.pbm_hw, (MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM) >> 3));
                hw_ldp_ext = mem_param->member.ldp_ext;
            }
            else
            {
            sys_met_t dsmet;
            sal_memset(&dsmet, 0, sizeof(dsmet));
            CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, p_meminfo->dsmet.entry_type, p_meminfo->dsmet.dsmet_offset, &dsmet));
            sal_memcpy(p_member->pbm_hw, dsmet.port_bitmap, (MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM) >> 3));
            hw_ldp_ext = dsmet.ldp_ext;
            }
        }

        /*nexthop mcast add bridge member, MEM_BITMAP type cannot remove.*/
        if (!p_member->is_del || (CTC_FLAG_ISSET(p_member->pbm_hw[0], p_member->pbm[0]) && CTC_FLAG_ISSET(p_member->pbm_hw[1], p_member->pbm[1])))
        {
            is_match_bitmap = 1;
        }

         switch (p_member->member_type)
         {
         case  SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE:
         case  SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH:
         case  SYS_NH_PARAM_IPMC_MEM_LOOP_BACK:
             if ((p_meminfo->dsmet.ref_nhid == p_member->ref_nhid) && (p_meminfo->dsmet.fid == p_member->fid) && !CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_EN))
             {
                 sys_usw_global_get_xgpon_en(lchip, &xgpon_en);
                 if (xgpon_en && (p_member->is_logic_port))
                 {
                     if (p_meminfo->dsmet.logic_port == p_member->logic_port)
                     {
                         *pp_mem_node = p_meminfo;
                         *p_entry_exit = TRUE;
                         return CTC_E_NONE;
                     }
                 }
                 else
                 {
                     *pp_mem_node = p_meminfo;
                     *p_entry_exit = TRUE;
                     return CTC_E_NONE;
                 }
             }
             break;
         case SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID:
            SYS_MC_MAP_PBM_PORT_ID(p_member->destid, port_type, port_id);
            if (!p_member->is_logic_port && !p_member->ldp_ext && CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM)
                && CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) == p_member->is_linkagg
                && (SYS_MC_DESTID_IS_NOT_TOCPU(p_member->destid))
                && (p_meminfo->dsmet.ref_nhid == p_member->ref_nhid)
                && (p_meminfo->dsmet.fid == p_member->fid)
                && ((refect_en == !CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD)) || p_member->is_del))
            {
                if ((port_type == p_meminfo->dsmet.port_type) && !p_member->is_del)
                {
                    *pp_mem_node = p_meminfo;
                    *p_entry_exit = CTC_BMP_ISSET(p_member->pbm_hw, port_id);
                    return CTC_E_NONE;
                }
                else if ((port_type == p_meminfo->dsmet.port_type) && CTC_BMP_ISSET(p_member->pbm_hw, port_id))
                {
                    *pp_mem_node = p_meminfo;
                    *p_entry_exit = TRUE;
                    return CTC_E_NONE;
                }
            }
            else if (
                CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) == p_member->is_linkagg
                && (p_meminfo->dsmet.ucastid == p_member->destid)
                && (p_meminfo->dsmet.ref_nhid == p_member->ref_nhid)
                && (hw_ldp_ext == p_member->ldp_ext)
                && ((refect_en == !CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD)) ||  p_member->is_del)
                && !CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_EN)
                && !CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM))
            {
                *pp_mem_node = p_meminfo;
                *p_entry_exit = TRUE;
                return CTC_E_NONE;
            }
            break;

        case SYS_NH_PARAM_MCAST_MEM_MIRROR_WITH_NH:
            if (p_meminfo->dsmet.ref_nhid == p_member->ref_nhid)
            {
                *pp_mem_node = p_meminfo;
                *p_entry_exit = TRUE;
                return CTC_E_NONE;
            }

            break;

        case SYS_NH_PARAM_BRGMC_MEM_LOCAL:
        case SYS_NH_PARAM_BRGMC_MEM_RAPS:
            SYS_MC_MAP_PBM_PORT_ID(p_member->destid, port_type, port_id);
            if ((!p_member->is_logic_port || (sys_usw_nh_is_xgpon_hybrid(lchip, p_member->logic_port) && (p_meminfo->dsmet.logic_port == p_member->logic_port))) 
                && CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM)
                && (CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) == p_member->is_linkagg)
            && (SYS_MC_DESTID_IS_NOT_TOCPU(p_member->destid))
            && ((refect_en == !CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD)) || p_member->is_del))
            {
                if ((port_type == p_meminfo->dsmet.port_type) && !p_member->is_del)
                {
                     *pp_mem_node = p_meminfo;
                     *p_entry_exit = CTC_BMP_ISSET(p_member->pbm_hw, port_id);
                     return CTC_E_NONE;
                }
                else if ((port_type == p_meminfo->dsmet.port_type) && CTC_BMP_ISSET(p_member->pbm_hw, port_id))
                {
                    *pp_mem_node = p_meminfo;
                    *p_entry_exit = TRUE;
                    return CTC_E_NONE;
                }
            }
            else if (
                CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) == p_member->is_linkagg &&
                p_meminfo->dsmet.ucastid == p_member->destid &&
                CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_PORT_CHK) == p_member->is_logic_port &&
                p_meminfo->dsmet.logic_port == p_member->logic_port &&
                ((refect_en == !CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD)) || p_member->is_del))
            {
                *pp_mem_node = p_meminfo;
                *p_entry_exit = TRUE;
                return CTC_E_NONE;
            }
            break;
       case SYS_NH_PARAM_BRGMC_MEM_BITMAP:
           if ((!p_member->is_logic_port && (0 == p_meminfo->dsmet.logic_port)) 
                && !p_member->is_linkagg && CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM)
                && (!CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) ) && is_match_bitmap)
            { /*only suport port bitmap */
                 if (p_member->l3if_type == p_meminfo->dsmet.port_type)
                 {
                     *pp_mem_node = p_meminfo;
                    *p_entry_exit = TRUE;
                     return CTC_E_NONE;
                 }
            }
          break;
       case SYS_NH_PARAM_MCAST_MEM_REMOTE:

            if ((CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) == p_member->is_linkagg) &&
                (p_meminfo->dsmet.ucastid == p_member->destid))
            {
                *pp_mem_node = p_meminfo;
                *p_entry_exit = TRUE;
                return CTC_E_NONE;
            }

            break;

        case  SYS_NH_PARAM_IPMC_MEM_LOCAL:
                if ((((0 == p_member->is_logic_port) && (0 == p_meminfo->dsmet.logic_port)) || (sys_usw_nh_is_xgpon_hybrid(lchip, p_member->logic_port) && (p_meminfo->dsmet.logic_port == p_member->logic_port))) 
                &&  CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM)
                && (p_member->l3if_type == CTC_L3IF_TYPE_VLAN_IF)
                && (p_meminfo->dsmet.vid == p_member->vid)
                && CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) == p_member->is_linkagg
                && (p_member->leaf_check_en == CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_LEAF_CHECK_EN)))
            {
                 uint8 port_type = 0;
                 uint16 port_id = 0;
                 SYS_MC_MAP_PBM_PORT_ID(p_member->destid, port_type, port_id);
                 SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "port_type:%d, port_id:%d\n", port_type, port_id);

                 if (port_type == p_meminfo->dsmet.port_type)
                 {
                     *pp_mem_node = p_meminfo;
                     *p_entry_exit = CTC_BMP_ISSET(p_member->pbm_hw, port_id);
                     return CTC_E_NONE;
                 }
            }
            else
            {
                if ((CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) == p_member->is_linkagg)
                    && (p_meminfo->dsmet.ucastid == p_member->destid)
                    && (p_meminfo->dsmet.vid == p_member->vid)
                    && (p_meminfo->dsmet.cvid == p_member->cvid)
                    && (p_member->leaf_check_en == CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_LEAF_CHECK_EN)))
                {
                    *pp_mem_node = p_meminfo;
                    *p_entry_exit = TRUE;
                    return CTC_E_NONE;
                }
            }
            break;

        case SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP:  /* logic replication  */
            /* logic replication  */
            if ((CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) == p_member->is_linkagg)
                && (p_meminfo->dsmet.ucastid == p_member->destid))
            {
                 uint16 max_repli_num = 0;

                 max_repli_num = DRV_FROM_TMM(lchip)?SYS_NH_LOGICAL_REPLI_NUM:SYS_NH_LOGICAL_REPLI_MAX_NUM;

                if ((p_meminfo->dsmet.replicate_num + 1) < max_repli_num)
                {
                    *pp_mem_node = p_meminfo;
                }

                if (p_meminfo->dsmet.replicate_num == 0)
                {
                    if (p_meminfo->dsmet.vid == p_member->vid)
                    {
                        *p_entry_exit = TRUE;
                        *pp_mem_node = p_meminfo;
                        return CTC_E_NONE;
                    }
                }
                else
                {
                    for (index = 0; index < (p_meminfo->dsmet.replicate_num + 1); index++)
                    {
                        if (p_meminfo->dsmet.vid_list[index] == p_member->vid)
                        {
                            *p_repli_pos = index;
                            *p_entry_exit = TRUE;
                            *pp_mem_node = p_meminfo;
                            return CTC_E_NONE;
                        }
                    }
                }
            }
            break;

        case SYS_NH_PARAM_MCAST_MEM_LOCAL_LOGIC_REP: /* logic replication */
            /* logic replication  */
            if ((CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG) == p_member->is_linkagg)
                && (p_meminfo->dsmet.ucastid == p_member->destid))
            {
                 uint32 offset = 0;
                 uint8 use_dsnh8w = 0;
                 uint8 max_num = 0;
                 CTC_ERROR_RETURN(_sys_usw_nh_get_dsnh_offset_by_nhid(lchip, p_member->ref_nhid, &offset, &use_dsnh8w));

                max_num = use_dsnh8w?(SYS_NH_LOGICAL_REPLI_MAX_NUM*2): SYS_NH_LOGICAL_REPLI_MAX_NUM;

                if ((p_meminfo->dsmet.replicate_num + 1) < SYS_NH_LOGICAL_REPLI_MAX_NUM &&
                    offset >= (p_meminfo->dsmet.dsnh_offset/max_num)*max_num &&
                    offset < (p_meminfo->dsmet.dsnh_offset/max_num + 1)*max_num)
                {
                    *pp_mem_node = p_meminfo;
                }

                if (p_meminfo->dsmet.replicate_num == 0)
                {
                    if (p_meminfo->dsmet.ref_nhid == p_member->ref_nhid)
                    {
                        *p_entry_exit = TRUE;
                        *pp_mem_node = p_meminfo;
                        return CTC_E_NONE;
                    }
                }
                else
                {
                    for (index = 0; index < (p_meminfo->dsmet.replicate_num + 1)*2; index++)
                    {
                        if (p_meminfo->dsmet.vid_list[index] == p_member->ref_nhid)
                        {
                            *p_repli_pos = index;
                            *p_entry_exit = TRUE;
                            *pp_mem_node = p_meminfo;
                            return CTC_E_NONE;
                        }
                    }
                }
            }
            break;
        case SYS_NH_PARAM_MEM_LOGIC_REP_LIST:
            {
                if(((p_meminfo->dsmet.vid == p_member->vid)&&(0 != p_member->vid))
                    || ((p_meminfo->dsmet.ref_nhid == p_member->ref_nhid)&&(0 != p_member->ref_nhid)))
                {
                    *p_entry_exit = TRUE;
                    *pp_mem_node = p_meminfo;
                    return CTC_E_NONE;
                }
            }
            break;
        default:
            break;
        }
    }


    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_mcast_repli_update_dsnh(uint8 lchip, uint32 old_dsnh_offset,
                                          uint32 new_dsnh_offset, uint32 update_cnt)
{
    DsNextHop4W_m dsnh[SYS_NH_LOGICAL_REPLI_MAX_NUM];
    uint32 cmd = 0;
    uint32 offset = 0;
    uint32 i = 0;

    cmd = DRV_IOR(DsNextHop4W_t, DRV_ENTRY_FLAG);
    for (i = 0; i < update_cnt ; i++)
    {
        offset = old_dsnh_offset + i;
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, offset, cmd, &dsnh[i]));
    }


    cmd = DRV_IOW(DsNextHop4W_t, DRV_ENTRY_FLAG);
    for (i = 0; i < update_cnt ; i++)
    {
        offset = new_dsnh_offset + i;
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, offset, cmd, &dsnh[i]));
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_mcast_rep_process_dsnh(uint8 lchip, sys_nh_param_mcast_member_t* p_mem_param,
                                     sys_nh_mcast_meminfo_t* p_member_info,
                                     uint32* p_dsnh_offset,
                                     uint8* p_use_dsnh8w)
{
    uint8 dsnh_is_8w = 0;
    uint32 dsnh_offset = 0;
    uint8 max_num = 0;

    CTC_ERROR_RETURN(_sys_usw_nh_get_dsnh_offset_by_nhid(lchip, p_mem_param->ref_nhid, &dsnh_offset, &dsnh_is_8w));

    max_num = dsnh_is_8w?(SYS_NH_LOGICAL_REPLI_MAX_NUM*2): SYS_NH_LOGICAL_REPLI_MAX_NUM;

    if (p_member_info)     /*Update dsnh offset*/
    {
        if (p_member_info->dsmet.vid_list)
        {
            *p_dsnh_offset = dsnh_offset;
            p_member_info->dsmet.vid_list[dsnh_offset%max_num] = p_mem_param->ref_nhid;
        }
        else
        {

            p_member_info->dsmet.vid_list = mem_malloc(MEM_NEXTHOP_MODULE, max_num * sizeof(uint16));

            if (!p_member_info->dsmet.vid_list)
            {
                return CTC_E_NO_MEMORY;
            }

            /*First nexhtop*/
            p_member_info->dsmet.vid_list[p_member_info->dsmet.dsnh_offset%max_num] = p_member_info->dsmet.ref_nhid;

            /*Current nexhtop*/
           *p_dsnh_offset = dsnh_offset;
            p_member_info->dsmet.vid_list[dsnh_offset%max_num] = p_mem_param->ref_nhid;

            /*update met ds nexthop offset*/
            p_member_info->dsmet.dsnh_offset = (dsnh_offset / max_num)*max_num;
        }


    }
    else
    {
        *p_dsnh_offset = dsnh_offset;
    }


   *p_use_dsnh8w = dsnh_is_8w;

    return CTC_E_NONE;
}

STATIC  int32
_sys_usw_nh_mcast_process_dsnh(uint8 lchip, sys_nh_param_mcast_member_t* p_mem_param,
                                     sys_nh_mcast_meminfo_t* p_member_info,
                                     uint32* p_dsnh_offset)
{

    sys_nh_param_dsnh_t dsnh_param;
    sys_l3if_prop_t l3if_prop;
    uint8 entry_num = 0;

    sal_memset(&dsnh_param, 0, sizeof(sys_nh_param_dsnh_t));

    if (p_mem_param->is_linkagg)
    {
        l3if_prop.gport = CTC_MAP_TID_TO_GPORT(p_mem_param->destid);
    }
    else
    {
        uint8 gchip;
        CTC_ERROR_RETURN(sys_usw_get_gchip_id(lchip, &gchip));
        l3if_prop.gport = CTC_MAP_LPORT_TO_GPORT(gchip, p_mem_param->destid);
    }

    l3if_prop.l3if_type = p_mem_param->l3if_type;
    l3if_prop.vlan_id = p_mem_param->vid & 0xFFF;
    l3if_prop.cvlan_id = p_mem_param->cvid & 0xFFF;

    CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_info(lchip, 0, &l3if_prop));
    dsnh_param.l2edit_ptr = 0;
    dsnh_param.l3edit_ptr = 0;
    dsnh_param.dest_vlan_ptr = l3if_prop.vlan_ptr;

    if (p_member_info && p_member_info->dsmet.free_dsnh_offset_cnt)
    /*Logical replicate*/
    {
        if (p_member_info->dsmet.replicate_num + 1 >= SYS_NH_LOGICAL_REPLI_MAX_NUM)
        {
            return CTC_E_INVALID_PARAM;
        }

        *p_dsnh_offset = p_member_info->dsmet.dsnh_offset + p_member_info->dsmet.replicate_num + 1;
        p_member_info->dsmet.free_dsnh_offset_cnt--;
        p_member_info->dsmet.vid_list[p_member_info->dsmet.replicate_num + 1] = l3if_prop.vlan_id;

    }
    else if (p_member_info)
    /*Update dsnh offset*/
    {
        /*Logical replicate*/
        if (p_member_info->dsmet.vid_list == NULL)
        {
            p_member_info->dsmet.vid_list = mem_malloc(MEM_NEXTHOP_MODULE, SYS_NH_LOGICAL_REPLI_MAX_NUM * sizeof(uint16));

            if (!p_member_info->dsmet.vid_list)
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
			return CTC_E_NO_MEMORY;

            }

            p_member_info->dsmet.vid_list[0] = p_member_info->dsmet.vid;
            CTC_UNSET_FLAG(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_USE_RSV_NH);
        }

        if ((p_member_info->dsmet.replicate_num + 1) < SYS_NH_MCAST_REPLI_INCR_STEP)
        {
            entry_num = SYS_NH_MCAST_REPLI_INCR_STEP;
        }
        else
        {
            entry_num = p_member_info->dsmet.replicate_num + 1 + SYS_NH_MCAST_REPLI_INCR_STEP;
        }

        /*Allocate new dsnh*/
        CTC_ERROR_RETURN(sys_usw_nh_offset_alloc(lchip,
                                                        SYS_NH_ENTRY_TYPE_NEXTHOP_4W, entry_num, p_dsnh_offset));

        /*Free old dsnh offset*/
        CTC_ERROR_RETURN(sys_usw_nh_offset_free(lchip,
                                                       SYS_NH_ENTRY_TYPE_NEXTHOP_4W, (p_member_info->dsmet.replicate_num + 1),
                                                       (p_member_info->dsmet.dsnh_offset)));

        CTC_ERROR_RETURN(_sys_usw_nh_mcast_repli_update_dsnh(lchip,
                                                                    p_member_info->dsmet.dsnh_offset, (*p_dsnh_offset), (p_member_info->dsmet.replicate_num + 1)));

        p_member_info->dsmet.free_dsnh_offset_cnt = SYS_NH_MCAST_REPLI_INCR_STEP;

        p_member_info->dsmet.free_dsnh_offset_cnt -= ((p_member_info->dsmet.replicate_num) ? 1 : 2);

        p_member_info->dsmet.vid_list[p_member_info->dsmet.replicate_num + 1] = l3if_prop.vlan_id;
        p_member_info->dsmet.dsnh_offset = *p_dsnh_offset;

        /*Current used dsnh offset*/
        *p_dsnh_offset = (*p_dsnh_offset) + p_member_info->dsmet.replicate_num + 1;


    }
    else
    {   /*First member */
        CTC_ERROR_RETURN(sys_usw_nh_offset_alloc(lchip,
                                                        SYS_NH_ENTRY_TYPE_NEXTHOP_4W,
                                                        1, p_dsnh_offset));

    }

    dsnh_param.dsnh_offset = (*p_dsnh_offset);
    dsnh_param.dsnh_type = SYS_NH_PARAM_DSNH_TYPE_IPMC;
    dsnh_param.mtu_no_chk = p_mem_param->mtu_no_chk;
    CTC_ERROR_RETURN(sys_usw_nh_write_entry_dsnh4w(lchip, &dsnh_param));
    return CTC_E_NONE;

}


STATIC  int32
_sys_usw_nh_mcast_entry_set_default(uint8 lchip,
                                           sys_nh_info_mcast_t* p_info_mcast,
                                           uint32 met_offset,
                                           bool bCreateGroup,
                                           bool bIs6w)
{

    sys_nh_info_dsmet_t dsmet;
    sys_nh_param_mcast_member_t mem_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    sal_memset(&dsmet, 0, sizeof(sys_nh_info_dsmet_t));
    sal_memset(&mem_param, 0, sizeof(sys_nh_param_mcast_member_t));

    dsmet.dsmet_offset = met_offset;
    dsmet.entry_type = (g_usw_nh_master[lchip]->met_mode || CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_2X_GRP_ID))?SYS_NH_ENTRY_TYPE_MET_6W : SYS_NH_ENTRY_TYPE_MET;
    if (DRV_FROM_AT(lchip) && g_usw_nh_master[lchip]->met_mode)
    {
        dsmet.entry_type = SYS_NH_ENTRY_TYPE_MET;/*use DsMetEntry1X*/
    }
    dsmet.ucastid = SYS_NH_MET_DROP_UCAST_ID;
    CTC_SET_FLAG(dsmet.flag, SYS_NH_DSMET_FLAG_ENDLOCAL);
    /*TBD Should use callback function*/
    if ( p_info_mcast->profile_met_offset)
    {
        dsmet.next_dsmet_offset = p_info_mcast->profile_met_offset;
    }
    else
    {
        dsmet.next_dsmet_offset = SYS_NH_MET_END_REPLICATE_OFFSET;
    }
    mem_param.p_info_mcast = p_info_mcast;
    CTC_ERROR_RETURN(_sys_usw_nh_mcast_write_dsmet(lchip, &dsmet, &mem_param));
    return CTC_E_NONE;
}

int32
_sys_usw_nh_mcast_build_dsmet_info(uint8 lchip, sys_nh_info_mcast_t* p_info_mcast,
                                         sys_nh_mcast_dsmet_io_t* p_dsmet_io,
                                         sys_nh_info_dsmet_t* p_dsmet)
{

    if (p_dsmet_io->p_mem_param->member_type != SYS_NH_PARAM_BRGMC_MEM_BITMAP)
    {
        p_dsmet->replicate_num = 0;
    }
    p_dsmet->dsnh_offset = p_dsmet_io->dsnh_offset;
    p_dsmet->dsmet_offset = p_dsmet_io->met_offset;
    p_dsmet->member_type = p_dsmet_io->p_mem_param->member_type;
    p_dsmet->flag      |= p_dsmet_io->p_mem_param->is_linkagg ? SYS_NH_DSMET_FLAG_IS_LINKAGG : 0;
    p_dsmet->flag      |= p_dsmet_io->p_mem_param->is_logic_port ? SYS_NH_DSMET_FLAG_LOGIC_PORT_CHK : 0;
    p_dsmet->flag      |= p_dsmet_io->p_mem_param->is_horizon_split ? SYS_NH_DSMET_FLAG_HORIZON_SPLIT_EN : 0;
    p_dsmet->flag      |= p_dsmet_io->p_mem_param->is_reflective? SYS_NH_DSMET_FLAG_REFECTIVE: 0;
    p_dsmet->flag      |= p_dsmet_io->p_mem_param->is_destmap_profile? SYS_NH_DSMET_FLAG_DESTMAP_PROFILE: 0;
    p_dsmet->flag      |= p_dsmet_io->p_mem_param->leaf_check_en? SYS_NH_DSMET_FLAG_LEAF_CHECK_EN:0;
    p_dsmet->flag      |= p_dsmet_io->p_mem_param->logic_rep_ability? SYS_NH_DSMET_FLAG_LOGIC_REPLI_ABILITY:0;
    p_dsmet->flag      |= p_dsmet_io->p_mem_param->ldp_ext? SYS_NH_DSMET_FLAG_LDP_EXT_EN:0;

    p_dsmet->logic_port  = p_dsmet_io->p_mem_param->logic_port;
    p_dsmet->ref_nhid = p_dsmet_io->p_mem_param->ref_nhid;
    p_dsmet->vid      = p_dsmet_io->p_mem_param->vid;
    p_dsmet->cvid      = p_dsmet_io->p_mem_param->cvid;
    p_dsmet->ucastid = p_dsmet_io->p_mem_param->destid;
    switch (p_dsmet_io->p_mem_param->member_type)
    {
    case SYS_NH_PARAM_BRGMC_MEM_LOCAL:
    case SYS_NH_PARAM_BRGMC_MEM_BITMAP:
    case SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE:
    case SYS_NH_PARAM_BRGMC_MEM_RAPS:
    case SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH:
    case SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID:
        p_dsmet->flag      |= p_dsmet_io->p_mem_param->is_src_port_check_dis ? 0 : SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD;
        p_dsmet->flag      |= p_dsmet_io->p_mem_param->cloud_sec_en?SYS_NH_DSMET_FLAG_CLOUD_SEC_EN:0;
        if (SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH == p_dsmet_io->p_mem_param->member_type
            && sys_usw_nh_is_cpu_nhid(lchip, p_dsmet->ref_nhid))
        {
            uint32 reason_id = 0;
            sys_cpu_reason_dest_info_t dest_info;
            sal_memset(&dest_info, 0, sizeof(dest_info));
            reason_id = CTC_PKT_CPU_REASON_GET_BY_NHPTR(p_dsmet->dsnh_offset);
            CTC_ERROR_RETURN(sys_usw_cpu_reason_get_info(lchip, reason_id, &dest_info));
            p_dsmet->ucastid = ((dest_info.dest_map>>16)<<10)|(dest_info.dest_map&0x1FF);
            CTC_UNSET_FLAG(p_dsmet->flag, SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD);
        }
    /*No need break here*/
    case SYS_NH_PARAM_MCAST_MEM_LOCAL_LOGIC_REP:
    case SYS_NH_PARAM_MCAST_MEM_MIRROR_WITH_NH:
    case SYS_NH_PARAM_IPMC_MEM_LOCAL:
    case SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP:
    case SYS_NH_PARAM_IPMC_MEM_LOOP_BACK:
        if (p_dsmet_io->p_next_mem)
        {
            p_dsmet->next_dsmet_offset = p_dsmet_io->p_next_mem->dsmet.dsmet_offset;
        }
        else
        {
            CTC_SET_FLAG(p_dsmet->flag, SYS_NH_DSMET_FLAG_ENDLOCAL);
            p_dsmet->next_dsmet_offset = SYS_NH_MET_END_REPLICATE_OFFSET;
        }

        break;


    case SYS_NH_PARAM_MCAST_MEM_REMOTE:
        break;

    default:
        return CTC_E_INVALID_PARAM;

    }

    /*If stacking en, need hook stacking mcast group*/
    if (SYS_NH_MET_END_REPLICATE_OFFSET == p_dsmet->next_dsmet_offset
        && p_info_mcast->profile_met_offset)
    {
      p_dsmet->next_dsmet_offset = p_info_mcast->profile_met_offset;
    }

    return CTC_E_NONE;
}

STATIC  int32
_sys_usw_nh_mcast_add_dsmet_entry(uint8 lchip, sys_nh_param_mcast_member_t* p_mem_param,
                                        uint32 dsnh_offset,
                                        uint8 use_dsnh8w,
                                        void* p_member_node,
                                        sys_nh_info_mcast_t* p_info_mcast)
{
    int32 ret = CTC_E_NONE;
    sys_nh_mcast_meminfo_t* p_mem_flex = NULL;
    uint32 new_met_offset = 0;
    sys_nh_mcast_dsmet_io_t dsmet_io;
    sys_nh_mcast_meminfo_t* p_member_info;
    uint32 first_met_offset = 0;
    ctc_list_pointer_t* p_db_member_list = &p_info_mcast->p_mem_list;
    sys_nh_mcast_meminfo_t* last_node = p_member_node;
    uint8 use_6w = 0;

    if (p_mem_param->no_hw)
    {
        p_member_info = mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_mcast_meminfo_param_t));
    }
    else
    {
        p_member_info = mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_mcast_meminfo_t));
    }
    if (!p_member_info)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
        return CTC_E_NO_MEMORY;
    }

    sal_memset(p_member_info, 0, sizeof(sys_nh_mcast_meminfo_t));
    if(p_mem_param->no_hw)
    {
        sal_memcpy(&(((sys_nh_mcast_meminfo_param_t*)p_member_info)->member), p_mem_param, sizeof(sys_nh_param_mcast_member_t));
    }
    p_member_info->dsmet.flag |= use_dsnh8w ? SYS_NH_DSMET_FLAG_USE_DSNH8W : 0;
    p_member_info->dsmet.entry_type = (p_mem_param->fid && DRV_IS_TSINGMA(lchip))? SYS_NH_ENTRY_TYPE_MET_6W : SYS_NH_ENTRY_TYPE_MET;
    p_member_info->dsmet.flag |= p_mem_param->is_mcast_aps ? SYS_NH_DSMET_FLAG_IS_MCAST_APS : 0;
    p_member_info->dsmet.fid = p_mem_param->fid;
    p_member_info->dsmet.flag |= p_mem_param->logic_rep_ability ? SYS_NH_DSMET_FLAG_LOGIC_REPLI_ABILITY : 0;

    if ((SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID == p_mem_param->member_type) && p_mem_param->ref_nhid)
    {
        sys_nh_info_dsnh_t nh_info = {0};
        CTC_ERROR_GOTO(_sys_usw_nh_get_nhinfo(lchip, p_mem_param->ref_nhid, &nh_info), ret, error1);
        if (nh_info.logic_rep_list)
        {
            CTC_SET_FLAG(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_EN);
        }
    }

    /*1. Init param*/
    sal_memset(&dsmet_io, 0, sizeof(sys_nh_mcast_dsmet_io_t));
    dsmet_io.p_mem_param = p_mem_param;

    if ((SYS_NH_PARAM_BRGMC_MEM_LOCAL == p_mem_param->member_type ||
        SYS_NH_PARAM_BRGMC_MEM_RAPS == p_mem_param->member_type ||
        SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID == p_mem_param->member_type ||
    (SYS_NH_PARAM_IPMC_MEM_LOCAL == p_mem_param->member_type &&
    p_mem_param->l3if_type == CTC_L3IF_TYPE_VLAN_IF))
    && (!p_mem_param->is_logic_port || sys_usw_nh_is_xgpon_hybrid(lchip, p_mem_param->logic_port))
    && !p_mem_param->leaf_check_en
    && (SYS_MC_DESTID_IS_NOT_TOCPU(p_mem_param->destid)))
    {
        uint8 port_type = 0;
        uint16 port_id = 0;
        SYS_MC_MAP_PBM_PORT_ID(p_mem_param->destid, port_type, port_id);
        p_member_info->dsmet.port_type = port_type;
        p_member_info->dsmet.vid = p_mem_param->vid;
        p_member_info->dsmet.ucastid = p_mem_param->destid;
        p_member_info->dsmet.replicate_num  = 0;
        p_member_info->dsmet.entry_type = SYS_NH_ENTRY_TYPE_MET;

        /*reflective member only used for new added members,and reflective member only be used in linked lists*/
        if(!p_mem_param->is_src_port_check_dis && !p_mem_param->logic_rep_ability)
        {
           CTC_SET_FLAG(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM);
        }

        if((SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID == p_mem_param->member_type)
            || (SYS_NH_PARAM_IPMC_MEM_LOCAL == p_mem_param->member_type && p_mem_param->l3if_type == CTC_L3IF_TYPE_VLAN_IF)
            || p_mem_param->is_mirror || (sys_usw_nh_is_xgpon_hybrid(lchip, p_mem_param->logic_port)))
        {
            p_member_info->dsmet.entry_type = SYS_NH_ENTRY_TYPE_MET_6W;
            use_6w = 1;
        }

        /*new met usw port bitmap, pass pbmp to write dsmet entry*/
        if(CTC_FLAG_ISSET(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM))
        {
            sal_memset(p_mem_param->pbm_hw, 0, sizeof(p_mem_param->pbm_hw));
            CTC_BMP_SET(p_mem_param->pbm_hw, port_id);
            if (p_mem_param->no_hw)
            {
                sys_nh_mcast_meminfo_param_t* mem_param = (sys_nh_mcast_meminfo_param_t*)p_member_info;
                sal_memset(mem_param->member.pbm_hw, 0, sizeof(p_mem_param->pbm_hw));
                CTC_BMP_SET(mem_param->member.pbm_hw, port_id); 
            }
        }

    }
    else if (SYS_NH_PARAM_BRGMC_MEM_BITMAP == p_mem_param->member_type)
    {
          int32 count = 0;

          sal_memcpy(p_mem_param->pbm_hw, p_mem_param->pbm, MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM) >> 3);
          CTC_BMP_COUNT_RANGE(p_mem_param->pbm,count, 0, MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM));
          p_member_info->dsmet.replicate_num = count-1;
          p_info_mcast->physical_replication_num += count;
          p_member_info->dsmet.port_type = p_mem_param->l3if_type;
          p_member_info->dsmet.entry_type = SYS_NH_ENTRY_TYPE_MET;
          CTC_SET_FLAG(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM);
    }

    /*2. Build new allocate member, and update flex member(prev member or next member)*/
    /*2.1 New member is the list's first member*/
    if (ctc_list_pointer_empty(p_db_member_list))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Mcast list is empty!\n");
        p_member_info->dsmet.entry_type = (CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_2X_GRP_ID))?SYS_NH_ENTRY_TYPE_MET_6W:SYS_NH_ENTRY_TYPE_MET;
        dsmet_io.met_offset = p_info_mcast->basic_met_offset;
        first_met_offset = p_info_mcast->basic_met_offset;
        if ((use_6w || p_mem_param->fid)&&!(CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_2X_GRP_ID))
            && !p_mem_param->is_logic_port)
        {
            sys_nh_info_dsmet_t dsmet;
            sal_memset(&dsmet, 0, sizeof(sys_nh_info_dsmet_t));
            ret = (sys_usw_nh_offset_alloc(lchip, SYS_NH_ENTRY_TYPE_MET_6W, p_mem_param->no_hw? 0 : 1, &new_met_offset));
            if (ret)
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Alloc met offset failed!\n");
                goto error1;
            }

            dsmet.dsmet_offset = p_info_mcast->basic_met_offset;
            dsmet.next_dsmet_offset = new_met_offset;
            dsmet.entry_type = SYS_NH_ENTRY_TYPE_MET;
            dsmet.ucastid = SYS_NH_MET_DROP_UCAST_ID;
            ret = (_sys_usw_nh_mcast_write_dsmet(lchip, &dsmet, p_mem_param));
            if (ret)
            {
                sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_MET_6W, 1, new_met_offset);
                goto error1;
            }
            CTC_SET_FLAG(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_APPEND_DROP);
            dsmet_io.met_offset = new_met_offset;
            first_met_offset = new_met_offset;
            p_member_info->dsmet.entry_type = SYS_NH_ENTRY_TYPE_MET_6W;
        }

        if (CTC_FLAG_ISSET(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_IS_MCAST_APS))
        {
            ret = (sys_usw_nh_offset_alloc(lchip, SYS_NH_ENTRY_TYPE_MET, p_mem_param->no_hw? 0 : 1, &new_met_offset));
            if (ret)
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Alloc met offset failed!\n");
                goto error1;
            }
            p_member_info->dsmet.dsmet_offset = new_met_offset;
            dsmet_io.met_offset = new_met_offset;
            CTC_SET_FLAG(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_IS_BASIC_MET);
        }

        dsmet_io.dsnh_offset = dsnh_offset;
        dsmet_io.p_next_mem = NULL;
        CTC_ERROR_GOTO(_sys_usw_nh_mcast_build_dsmet_info(lchip, p_info_mcast, &dsmet_io, &(p_member_info->dsmet)), ret, error1);

        /*Add this new member to db member list*/
        ctc_list_pointer_insert_head(p_db_member_list, &(p_member_info->list_head));


        ret = _sys_usw_nh_mcast_write_dsmet(lchip,&(p_member_info->dsmet), p_mem_param);
        if (ret)
        {
            ctc_list_pointer_delete_head(p_db_member_list);
            goto error1;
        }
        if(first_met_offset == p_info_mcast->basic_met_offset)
        {
          CTC_SET_FLAG(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_BASC_OFFSET_USED);
        }
    }
    else
    {
       if(p_member_info->dsmet.entry_type == SYS_NH_ENTRY_TYPE_MET
        && !CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_BASC_OFFSET_USED)
        && !CTC_FLAG_ISSET(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_IS_MCAST_APS)
        && !CTC_FLAG_ISSET(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_ABILITY))
       {
          new_met_offset = p_info_mcast->basic_met_offset;
       }
      else
      {
        /*2.2 New member is not the list's first member*/
        ret = (sys_usw_nh_offset_alloc(lchip, p_member_info->dsmet.entry_type, p_mem_param->no_hw? 0 : (p_mem_param->is_mcast_aps? 2 : 1), &new_met_offset));
          if (ret)
           {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Alloc met offset failed!\n");

            goto error1;
          }
       }

        /*(1) insert new member into tail*/
        dsmet_io.met_offset = new_met_offset;
        dsmet_io.dsnh_offset = dsnh_offset;
        dsmet_io.p_next_mem = NULL;
        ret = (_sys_usw_nh_mcast_build_dsmet_info(lchip, p_info_mcast, &dsmet_io, &(p_member_info->dsmet)));
        if (ret)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Build met information failed!\n");
            goto error2;
        }

       if(p_member_info->dsmet.dsmet_offset == p_info_mcast->basic_met_offset)
       {
            /*The list have one member at least, so the tail node should not be NULL*/
             p_mem_flex = _ctc_container_of(ctc_list_pointer_head(p_db_member_list),
                                        sys_nh_mcast_meminfo_t, list_head);
             p_member_info->dsmet.next_dsmet_offset = p_mem_flex->dsmet.dsmet_offset;

          /*Add this new member to db member list*/
          ctc_list_pointer_insert_head(p_db_member_list, &(p_member_info->list_head));
          CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip,&(p_member_info->dsmet), p_mem_param), ret, error3);
          CTC_SET_FLAG(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_BASC_OFFSET_USED);

      }
     else
     {
          /*The list have one member at least, so the tail node should not be NULL*/
          p_mem_flex = last_node? last_node : _ctc_container_of(ctc_list_pointer_node_tail(p_db_member_list),
                                                                sys_nh_mcast_meminfo_t, list_head);
          if (!CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_ABILITY)
            && p_mem_param->is_ipmc_member && DRV_FROM_TMM(lchip))
          {
              if (p_mem_param->p_1st_node_vlanif)
              {
                  p_mem_flex = p_mem_param->p_1st_node_vlanif;
              }
              else
              {
                  CTC_SET_FLAG(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_1ST_VLANIF);
              }
          }

          /*Add this new member to db member list*/
          ctc_list_pointer_insert_after(p_db_member_list, &(p_mem_flex->list_head), &(p_member_info->list_head));
          if (CTC_FLAG_ISSET(p_mem_flex->dsmet.flag, SYS_NH_DSMET_FLAG_ENDLOCAL))
          {
              CTC_SET_FLAG(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_ENDLOCAL);
          }
          else
          {
              CTC_UNSET_FLAG(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_ENDLOCAL);
              p_member_info->dsmet.next_dsmet_offset = p_mem_flex->dsmet.next_dsmet_offset;
          }
          CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip,&(p_member_info->dsmet), p_mem_param), ret, error3);

           /*(2) update previous member's next met offset*/
          p_mem_flex->dsmet.next_dsmet_offset = p_member_info->dsmet.dsmet_offset;
          CTC_UNSET_FLAG(p_mem_flex->dsmet.flag, SYS_NH_DSMET_FLAG_ENDLOCAL);

          /*write previous met, need to recover port bmp from hw*/
          if (CTC_FLAG_ISSET(p_mem_flex->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM) && (0 == p_mem_param->no_hw))
          {
              sys_met_t dsmet;
              sal_memset(&dsmet, 0, sizeof(dsmet));
              CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, p_mem_flex->dsmet.entry_type, p_mem_flex->dsmet.dsmet_offset, &dsmet));
              sal_memcpy(p_mem_param->pbm_hw, dsmet.port_bitmap, (MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM) >> 3));
          }
          CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip, &(p_mem_flex->dsmet), p_mem_param),ret, error3);
     }

    }

    return CTC_E_NONE;

error3:
    if(p_member_info->dsmet.dsmet_offset == p_info_mcast->basic_met_offset)
    {
       ctc_list_pointer_delete_head(p_db_member_list);
    }
    else
    {
        ctc_list_pointer_delete(p_db_member_list, &(p_member_info->list_head));
    }
error2:
    if (new_met_offset)
    {
        sys_usw_nh_offset_free(lchip, p_member_info->dsmet.entry_type, (p_mem_param->is_mcast_aps?2:1), new_met_offset);
    }
error1:
    mem_free(p_member_info);
    return ret;
}

int32
_sys_usw_nh_mcast_del_dsmet_entry(uint8 lchip, sys_nh_param_mcast_member_t* p_mem_param,
                                    sys_nh_mcast_meminfo_t* p_mem_info,
                                    ctc_list_pointer_t* p_db_member_list,
                                    sys_nh_info_mcast_t* p_info_mcast)
{
    sys_nh_mcast_meminfo_t* p_mem_target, * p_mem_flex;
    uint32 temp_met_ptr = 0;
    uint8 _1st_met_drop = 0;
    uint8 _1st_met_rewrite = 0;
    sys_met_t dsmet;
    sal_memset(&dsmet, 0, sizeof(dsmet));
    /*1. Init param*/
    p_mem_target = _ctc_container_of(ctc_list_pointer_head(p_db_member_list),
                                     sys_nh_mcast_meminfo_t, list_head);

    /*2. Remove member*/
    if (ctc_list_pointer_head(p_db_member_list) == (&(p_mem_info->list_head)))
    /*Target member is first member*/
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Remove first memeber!\n");
        if( p_mem_info->dsmet.dsmet_offset == p_info_mcast->basic_met_offset
          || CTC_FLAG_ISSET(p_mem_target->dsmet.flag, SYS_NH_DSMET_FLAG_IS_MCAST_APS))
         {
            CTC_UNSET_FLAG(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_BASC_OFFSET_USED);
         }

        if (p_mem_target->list_head.p_next || CTC_FLAG_ISSET(p_mem_target->dsmet.flag, SYS_NH_DSMET_FLAG_IS_MCAST_APS))
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Exist next member!\n");

            /*Get next member*/
            p_mem_flex = _ctc_container_of(p_mem_target->list_head.p_next,
                                           sys_nh_mcast_meminfo_t, list_head);

            _1st_met_drop = (p_mem_flex && (p_mem_info->dsmet.dsmet_offset == p_info_mcast->basic_met_offset) &&
                            (((p_mem_flex->dsmet.entry_type == SYS_NH_ENTRY_TYPE_MET_6W) && !(CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_2X_GRP_ID))
                                                                                         && !(CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_4X_GRP_ID)))
                            ||((p_mem_flex->dsmet.entry_type == SYS_NH_ENTRY_TYPE_MET_12W) && !(CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_4X_GRP_ID)))));
            _1st_met_rewrite = (p_mem_flex && (p_mem_info->dsmet.dsmet_offset != p_info_mcast->basic_met_offset) && DRV_FROM_AT(lchip));/*first node but not the first met*/

            if ((_1st_met_drop || _1st_met_rewrite) && p_mem_flex)
            {
                sal_memset(&p_mem_target->dsmet, 0, sizeof(sys_nh_info_dsmet_t));
                p_mem_target->dsmet.dsmet_offset = p_info_mcast->basic_met_offset;
                p_mem_target->dsmet.next_dsmet_offset = p_mem_flex->dsmet.dsmet_offset;
                p_mem_target->dsmet.entry_type = SYS_NH_ENTRY_TYPE_MET;
                p_mem_target->dsmet.ucastid = SYS_NH_MET_DROP_UCAST_ID;
                CTC_ERROR_RETURN(_sys_usw_nh_mcast_write_dsmet(lchip, &p_mem_target->dsmet, p_mem_param));
                if (_1st_met_rewrite)
                {
                    CTC_ERROR_RETURN(sys_usw_nh_offset_free(lchip, p_mem_info->dsmet.entry_type, 1, p_mem_info->dsmet.dsmet_offset));
                }
            }
            else
            {
                if (CTC_FLAG_ISSET(p_mem_target->dsmet.flag, SYS_NH_DSMET_FLAG_IS_MCAST_APS) && !p_mem_flex)
                {
                    CTC_ERROR_RETURN(sys_usw_nh_offset_free(lchip, p_mem_target->dsmet.entry_type,
                                                               1, p_mem_target->dsmet.dsmet_offset));
                    CTC_ERROR_RETURN(_sys_usw_nh_mcast_entry_set_default(lchip, p_info_mcast, p_info_mcast->basic_met_offset, TRUE, TRUE));
                }
                else if(p_mem_flex)
                {
                    /*Next member use pbm, recover from hw and then write to dsmet*/
                    if(CTC_FLAG_ISSET(p_mem_flex->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM)||
                        CTC_FLAG_ISSET(p_mem_flex->dsmet.flag, SYS_NH_DSMET_FLAG_LDP_EXT_EN))
                    {
                        CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, p_mem_flex->dsmet.entry_type, p_mem_flex->dsmet.dsmet_offset, &dsmet));
                        sal_memcpy(p_mem_param->pbm_hw, dsmet.port_bitmap, (MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM) >> 3));
                        p_mem_param->ldp_ext = dsmet.ldp_ext;
                    }
                    CTC_ERROR_RETURN(sys_usw_nh_offset_free(lchip, p_mem_flex->dsmet.entry_type, 1, p_mem_flex->dsmet.dsmet_offset));
                    if (CTC_FLAG_ISSET(p_mem_target->dsmet.flag, SYS_NH_DSMET_FLAG_IS_MCAST_APS))
                    {
                        CTC_ERROR_RETURN(sys_usw_nh_offset_free(lchip, p_mem_target->dsmet.entry_type, 1, p_mem_target->dsmet.dsmet_offset));
                    }
                    temp_met_ptr = p_mem_flex->dsmet.dsmet_offset;
                    p_mem_flex->dsmet.dsmet_offset = CTC_FLAG_ISSET(p_mem_target->dsmet.flag, SYS_NH_DSMET_FLAG_IS_MCAST_APS)?
                        p_info_mcast->basic_met_offset:p_mem_target->dsmet.dsmet_offset;
                    p_mem_flex->dsmet.entry_type = p_mem_target->dsmet.entry_type;
                    if (CTC_FLAG_ISSET(p_mem_flex->dsmet.flag, SYS_NH_DSMET_FLAG_IS_MCAST_APS))
                    {
                        p_mem_flex->dsmet.dsmet_offset = temp_met_ptr + 1;
                        CTC_SET_FLAG(p_mem_flex->dsmet.flag, SYS_NH_DSMET_FLAG_IS_BASIC_MET);
                    }

                    CTC_ERROR_RETURN(_sys_usw_nh_mcast_write_dsmet(lchip, &(p_mem_flex->dsmet), p_mem_param));
                    /*nextmet replace first basic met entry*/
                    CTC_SET_FLAG(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_BASC_OFFSET_USED);

                }
            }

        }
        else
        /*This is the last member of this group in this chip, deinit basic met entry*/
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Remove member is the last member!\n");

            if (CTC_FLAG_ISSET(p_mem_target->dsmet.flag, SYS_NH_DSMET_FLAG_APPEND_DROP) || (p_mem_info->dsmet.dsmet_offset != p_info_mcast->basic_met_offset))
            {
                CTC_ERROR_RETURN(sys_usw_nh_offset_free(lchip, p_mem_target->dsmet.entry_type,
                                                               1, p_mem_target->dsmet.dsmet_offset));
                p_mem_target->dsmet.dsmet_offset = p_info_mcast->basic_met_offset;
            }
            /*Free basic met offset*/
            CTC_ERROR_RETURN(_sys_usw_nh_mcast_entry_set_default(lchip, p_info_mcast, p_mem_target->dsmet.dsmet_offset, TRUE, TRUE));
        }
    }
    else
    {
        p_mem_flex = _ctc_container_of(p_mem_info->list_head.p_prev, sys_nh_mcast_meminfo_t, list_head);
        if (SYS_NH_PARAM_MCAST_MEM_REMOTE != p_mem_info->dsmet.member_type &&
            !CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE))
        {
            if (CTC_FLAG_ISSET(p_mem_info->dsmet.flag, SYS_NH_DSMET_FLAG_ENDLOCAL))
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Remove member is the last member!\n");
                CTC_SET_FLAG(p_mem_flex->dsmet.flag, SYS_NH_DSMET_FLAG_ENDLOCAL);
                if (p_info_mcast->profile_met_offset)
                {
                    p_mem_info->dsmet.next_dsmet_offset = p_info_mcast->profile_met_offset;
                }
                else
                {
                    p_mem_info->dsmet.next_dsmet_offset = SYS_NH_MET_END_REPLICATE_OFFSET;
                }
            }
            else
            {
                CTC_UNSET_FLAG(p_mem_flex->dsmet.flag, SYS_NH_DSMET_FLAG_ENDLOCAL);
            }
        }

        if (p_mem_info->list_head.p_next && (p_mem_param->p_1st_node_vlanif == p_mem_info) && DRV_FROM_TMM(lchip))
        {
            sys_nh_mcast_meminfo_t* p_mem_next = NULL;
            uint32 old_met_offset = 0;
            uint32 new_met_offset = 0;
            int32 ret = CTC_E_NONE;
            p_mem_next = _ctc_container_of(p_mem_info->list_head.p_next, sys_nh_mcast_meminfo_t, list_head);
            if (((SYS_NH_PARAM_IPMC_MEM_LOCAL == p_mem_next->dsmet.member_type)
                && CTC_FLAG_ISSET(p_mem_next->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM)
            && (!CTC_FLAG_ISSET(p_mem_next->dsmet.flag, SYS_NH_DSMET_FLAG_IS_LINKAGG))
            && (p_mem_next->dsmet.vid == p_mem_info->dsmet.vid))
            || (SYS_NH_PARAM_BRGMC_MEM_LOCAL == p_mem_next->dsmet.member_type))

            {
                CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, p_mem_next->dsmet.entry_type, p_mem_next->dsmet.dsmet_offset, &dsmet));
                sal_memcpy(p_mem_param->pbm_hw, dsmet.port_bitmap, (MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM) >> 3));
                p_mem_param->ldp_ext = dsmet.ldp_ext;
                ret = (sys_usw_nh_offset_alloc(lchip, p_mem_next->dsmet.entry_type, 1, &new_met_offset));
                if (CTC_E_NONE == ret)
                {
                    old_met_offset = p_mem_next->dsmet.dsmet_offset;
                    p_mem_next->dsmet.dsmet_offset = new_met_offset;
                    CTC_SET_FLAG(p_mem_next->dsmet.flag, SYS_NH_DSMET_FLAG_1ST_VLANIF);
                    CTC_ERROR_RETURN(_sys_usw_nh_mcast_write_dsmet(lchip, &(p_mem_next->dsmet), p_mem_param));
                    p_mem_info->dsmet.next_dsmet_offset = new_met_offset;
                    CTC_ERROR_RETURN(sys_usw_nh_offset_free(lchip, p_mem_next->dsmet.entry_type, 1, old_met_offset));
                }
                else
                {
                    CTC_SET_FLAG(p_mem_next->dsmet.flag, SYS_NH_DSMET_FLAG_1ST_VLANIF);
                    CTC_ERROR_RETURN(_sys_usw_nh_mcast_write_dsmet(lchip, &(p_mem_next->dsmet), p_mem_param));
                }
            }
        }

        p_mem_flex->dsmet.next_dsmet_offset = p_mem_info->dsmet.next_dsmet_offset;
        /*member use pbm, recover from hw and then write to dsmet*/
        if(CTC_FLAG_ISSET(p_mem_flex->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM)||
            CTC_FLAG_ISSET(p_mem_flex->dsmet.flag, SYS_NH_DSMET_FLAG_LDP_EXT_EN))
        {
            CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, p_mem_flex->dsmet.entry_type, p_mem_flex->dsmet.dsmet_offset, &dsmet));
            sal_memcpy(p_mem_param->pbm_hw, dsmet.port_bitmap, (MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM) >> 3));
            p_mem_param->ldp_ext = dsmet.ldp_ext;
        }
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_write_dsmet(lchip, &(p_mem_flex->dsmet), p_mem_param));
        CTC_ERROR_RETURN(sys_usw_nh_offset_free(lchip, p_mem_info->dsmet.entry_type,
                           (CTC_FLAG_ISSET(p_mem_info->dsmet.flag, SYS_NH_DSMET_FLAG_IS_MCAST_APS)?2:1), p_mem_info->dsmet.dsmet_offset));

    }

    ctc_list_pointer_delete(p_db_member_list, &(p_mem_info->list_head));
    if (p_mem_info->dsmet.vid_list)
    {
        mem_free(p_mem_info->dsmet.vid_list);
    }
    mem_free(p_mem_info);

    return CTC_E_NONE;
}

STATIC  int32
_sys_usw_nh_mcast_get_nh_and_edit_data(uint8 lchip, sys_nh_param_mcast_member_t* p_mem_param,
                                             sys_nh_mcast_meminfo_t* p_member_info,
                                             uint32* p_dsnh_offset, uint8* p_use_dsnh8w)
{

    uint32 dsnh_offset;
    sys_nh_info_dsnh_t nh_info;
    sal_memset(&nh_info,0,sizeof(sys_nh_info_dsnh_t));
    *p_use_dsnh8w = 0;

    switch (p_mem_param->member_type)
    {
    case SYS_NH_PARAM_BRGMC_MEM_LOCAL:
    case SYS_NH_PARAM_BRGMC_MEM_BITMAP:
        if (p_mem_param->is_mirror)
        {
            CTC_ERROR_RETURN(_sys_usw_nh_get_resolved_offset(lchip,
                                 SYS_NH_RES_OFFSET_TYPE_MIRROR_NH, p_dsnh_offset));
        }
        else if (sys_usw_nh_is_xgpon_hybrid(lchip, p_mem_param->logic_port))
        {
            CTC_ERROR_RETURN(sys_usw_nh_get_xgpon_flooding_dsnh(lchip, p_mem_param->logic_port, p_dsnh_offset, p_use_dsnh8w));
        }
        else
        {
            CTC_ERROR_RETURN(_sys_usw_nh_get_resolved_offset(lchip,
                                 SYS_NH_RES_OFFSET_TYPE_BRIDGE_NH, p_dsnh_offset));
        }

        break;


    case SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE:
         CTC_ERROR_RETURN(_sys_usw_nh_get_nhinfo(lchip, p_mem_param->ref_nhid, &nh_info));
        *p_dsnh_offset = (SYS_USW_DROP_NH_OFFSET == nh_info.dsnh_offset)?0:nh_info.dsnh_offset;
        *p_use_dsnh8w = nh_info.nexthop_ext;
        p_mem_param->cloud_sec_en = nh_info.cloud_sec_en;
        p_mem_param->is_destmap_profile = nh_info.use_destmap_profile;
       break;
    case SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH:
         CTC_ERROR_RETURN(_sys_usw_nh_get_nhinfo(lchip, p_mem_param->ref_nhid, &nh_info));
        *p_dsnh_offset = nh_info.dsnh_offset;
        *p_use_dsnh8w = nh_info.nexthop_ext;
         p_mem_param->cloud_sec_en = nh_info.cloud_sec_en;
         p_mem_param->is_destmap_profile = nh_info.use_destmap_profile;
         if (nh_info.use_destmap_profile)
         {
            p_mem_param->destid = DRV_FROM_TMM(lchip)?(((nh_info.dest_map&0x3ff)|(((nh_info.dest_map>>10)&0x3)<<12)|0x800))
                :((nh_info.dest_map & 0xffff) | 0x800);
         }
       break;
    case SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID:
    case SYS_NH_PARAM_MCAST_MEM_MIRROR_WITH_NH:
        CTC_ERROR_RETURN(_sys_usw_nh_get_dsnh_offset_by_nhid(lchip,
                             p_mem_param->ref_nhid, &dsnh_offset, p_use_dsnh8w));
        *p_dsnh_offset = dsnh_offset;
        break;

    case SYS_NH_PARAM_IPMC_MEM_LOCAL:
    case SYS_NH_PARAM_IPMC_MEM_LOOP_BACK:
        {
            sys_l3if_prop_t l3if_prop;
            CTC_ERROR_RETURN(_sys_usw_nh_mcast_get_l3if_nh_offset(lchip, p_mem_param, p_dsnh_offset));
            if (p_mem_param->is_linkagg)
            {
                l3if_prop.gport = CTC_MAP_TID_TO_GPORT(p_mem_param->destid);
            }
            else
            {
                uint8 gchip = 0;
                uint16 sys_lport = 0;
                CTC_ERROR_RETURN(sys_usw_get_gchip_id(lchip, &gchip));
                sys_lport = SYS_MAP_DRV_LPORT_TO_SYS_LPORT(p_mem_param->destid);
                l3if_prop.gport = CTC_MAP_LPORT_TO_GPORT(gchip, sys_lport);
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "L3if -> destid:0x%x, lport=%d, Gport:0x%x\n",
                               p_mem_param->destid, sys_lport, l3if_prop.gport);

            }

            l3if_prop.l3if_type = p_mem_param->l3if_type;
            l3if_prop.vlan_id = p_mem_param->vid & 0xFFF;
            l3if_prop.cvlan_id = p_mem_param->cvid & 0xFFF;

            if (SYS_NH_PARAM_IPMC_MEM_LOOP_BACK == p_mem_param->member_type)
            {
                l3if_prop.l3if_id = MCHIP_CAP(SYS_CAP_L3IF_RSV_L3IF_ID);
            }
            else
            {
                CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_info(lchip, 0, &l3if_prop));
            }
            CTC_ERROR_RETURN(sys_usw_nh_get_ipmc_dsnh_offset(lchip, l3if_prop.l3if_id, p_mem_param->logic_port, p_mem_param->mtu_no_chk, p_dsnh_offset));

        }
        break;

    case SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP:
            CTC_ERROR_RETURN(_sys_usw_nh_mcast_process_dsnh(lchip, p_mem_param, p_member_info, p_dsnh_offset));
        break;

    case SYS_NH_PARAM_MCAST_MEM_LOCAL_LOGIC_REP:
            CTC_ERROR_RETURN(_sys_usw_nh_mcast_rep_process_dsnh(lchip, p_mem_param, p_member_info, p_dsnh_offset, p_use_dsnh8w));
        break;

    case SYS_NH_PARAM_MCAST_MEM_REMOTE:
        break;

    case SYS_NH_PARAM_BRGMC_MEM_RAPS:
        if (DRV_FROM_AT(lchip))
        {
            CTC_ERROR_RETURN(_sys_usw_nh_get_resolved_offset(lchip,
                                                             SYS_NH_RES_OFFSET_TYPE_BRIDGE_NH, p_dsnh_offset));
        }
        else
        {
            *p_dsnh_offset = 0;
        }
        break;

    default:
        return CTC_E_INVALID_PARAM;
    }

    return CTC_E_NONE;
}

STATIC  int32
_sys_usw_nh_mcast_free_nh_and_edit_data(uint8 lchip,
                                              sys_nh_mcast_meminfo_t* p_member_info,
                                              uint32 del_pos)
{
    uint32 dsnh_offset_del, dsnh_offset_last;

    if (p_member_info->dsmet.member_type == SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP)
    {
        if (p_member_info->dsmet.replicate_num > 0)
        /*Remove none last member*/
        {
            dsnh_offset_last  = p_member_info->dsmet.dsnh_offset + p_member_info->dsmet.replicate_num;
            dsnh_offset_del  = p_member_info->dsmet.dsnh_offset + del_pos;
            /*Update dsnh table*/
            CTC_ERROR_RETURN(_sys_usw_nh_mcast_repli_update_dsnh(lchip, dsnh_offset_last, dsnh_offset_del, 1));

            p_member_info->dsmet.vid_list[del_pos] = p_member_info->dsmet.vid_list[p_member_info->dsmet.replicate_num];
            if (0 == del_pos)
            {
                p_member_info->dsmet.vid = p_member_info->dsmet.vid_list[del_pos];
            }

            p_member_info->dsmet.free_dsnh_offset_cnt++;

            if (SYS_NH_MCAST_REPLI_INCR_STEP == p_member_info->dsmet.free_dsnh_offset_cnt)
            {
                p_member_info->dsmet.free_dsnh_offset_cnt = 0;
                CTC_ERROR_RETURN(sys_usw_nh_offset_free(lchip,
                                                              SYS_NH_ENTRY_TYPE_NEXTHOP_4W,
                                                              SYS_NH_MCAST_REPLI_INCR_STEP,
                                                              dsnh_offset_last));


            }

        }
        else
        /*Remove last member*/
        {
            uint8 entry_num = 0;

            if (p_member_info->dsmet.vid_list)
            {
                entry_num = SYS_NH_MCAST_REPLI_INCR_STEP;
            }
            else
            {
                entry_num = 1;
            }

            CTC_ERROR_RETURN(sys_usw_nh_offset_free(lchip,
                                                           SYS_NH_ENTRY_TYPE_NEXTHOP_4W,
                                                           entry_num,
                                                           p_member_info->dsmet.dsnh_offset));

        }
    }
    else if(p_member_info->dsmet.member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_LOGIC_REP)
    {
        if (p_member_info->dsmet.replicate_num > 0)
            /*Remove none last member*/
        {
            uint8 last_pos = 0;
            uint16 last_nhid = 0;
            uint8  multi = 0;

            multi  = CTC_FLAG_ISSET(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_USE_DSNH8W)?2:1;
            last_pos = p_member_info->dsmet.replicate_num*multi;
            last_nhid =  p_member_info->dsmet.vid_list[last_pos];

            CTC_ERROR_RETURN(sys_usw_nh_swap_nexthop_offset(lchip, p_member_info->dsmet.vid_list[del_pos], last_nhid));

            p_member_info->dsmet.vid_list[del_pos] = last_nhid;
            if (1 == p_member_info->dsmet.replicate_num)
            {
                p_member_info->dsmet.ref_nhid = p_member_info->dsmet.vid_list[0];
            }


        }
        else     /*Remove last member*/
        {

            mem_free(p_member_info->dsmet.vid_list);
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "remove last member, nhid:%u, dsnh_offset:%u\n", p_member_info->dsmet.ref_nhid, p_member_info->dsmet.dsnh_offset);
        }

    }

    return CTC_E_NONE;
}

int32
_sys_usw_nh_mcast_add_member(uint8 lchip, sys_nh_param_mcast_member_t* p_mem_param,
                                   ctc_list_pointer_t* p_db_member_list,
                                   sys_nh_info_mcast_t* p_info_mcast)
{
    sys_nh_mcast_meminfo_t* p_member_info = NULL;
    bool entry_exist = FALSE;
    uint8 use_dsnh8w = 0;
    uint32 repli_pos = 0;
    uint32 dsnh_offset = 0;
    int32 ret = 0;
    sys_nh_info_dsnh_t nh_info;
    uint32 logic_rep_threshold = 0;
    uint8 phy_list_en = 0;
    sal_memset(&nh_info, 0, sizeof(nh_info));

    /*1. Check if mcast member have been existed*/
    CTC_PTR_VALID_CHECK(p_mem_param);

    if (p_mem_param->is_linkagg && (p_mem_param->destid >= SYS_USW_MAX_LINKAGG_GROUP_NUM))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Linkagg] Tid is invalid \n");
        return CTC_E_BADID;

    }

    if ((SYS_GET_CHIP_VERSION == SYS_CHIP_SUB_VERSION_A) && DRV_IS_TSINGMA(lchip) && p_mem_param->fid)
    {
        return CTC_E_NOT_SUPPORT;
    }
    if ((p_mem_param->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH) || (p_mem_param->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID))
    {
        CTC_ERROR_RETURN(_sys_usw_nh_get_nhinfo(lchip, p_mem_param->ref_nhid, &nh_info));
    }

    if (!p_mem_param->is_destmap_profile
             && (p_mem_param->destid >= SYS_USW_MAX_PORT_NUM_PER_CHIP)
             && (SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE != p_mem_param->member_type)
             && (SYS_NH_PARAM_MCAST_MEM_REMOTE != p_mem_param->member_type)
             && !sys_usw_nh_is_cpu_nhid(lchip, p_mem_param->ref_nhid))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Invalid localphy port \n");
        return CTC_E_INVALID_PORT;
    }

    p_mem_param->is_mirror = CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_IS_MIRROR);

    /*mcast mirrro only support local mirror*/
    if (p_mem_param->is_mirror
        && (p_mem_param->member_type > SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID))
    {
        return CTC_E_INVALID_PARAM;
    }

    if (p_mem_param->is_mirror
        && (p_mem_param->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH))
    {
        p_mem_param->member_type = SYS_NH_PARAM_MCAST_MEM_MIRROR_WITH_NH;
    }

    if ((p_mem_param->member_type == SYS_NH_PARAM_IPMC_MEM_LOCAL) &&
        (CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_EN)) && !p_mem_param->cvid)
    {
        p_mem_param->member_type = SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP;
    }

    if (p_mem_param->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH)
    {
        uint8 repli_en = 0;
        sys_usw_nh_is_logic_repli_en(lchip, p_mem_param->ref_nhid, &repli_en);
        if (repli_en && DRV_IS_DUET2(lchip))
        {
            p_mem_param->member_type = SYS_NH_PARAM_MCAST_MEM_LOCAL_LOGIC_REP;
        }
    }

    if (!p_mem_param->is_linkagg &&
        !p_mem_param->is_destmap_profile &&
        (SYS_NH_PARAM_MCAST_MEM_REMOTE != p_mem_param->member_type) &&
         p_mem_param->member_type != SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE)
    {
        p_mem_param->destid = SYS_MAP_SYS_LPORT_TO_DRV_LPORT(p_mem_param->destid);

        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "p_mem_param->destid:0x%x\n", p_mem_param->destid);

        if ((p_mem_param->member_type == SYS_NH_PARAM_BRGMC_MEM_LOCAL ||
             p_mem_param->member_type == SYS_NH_PARAM_IPMC_MEM_LOCAL)
             && SYS_MC_DESTID_IS_INTERNAL(p_mem_param->destid))
        {
            return CTC_E_INVALID_PARAM;
        }
    }

    /*get logic replicate ability*/
    CTC_ERROR_RETURN(sys_usw_global_ctl_get(lchip, CTC_GLOBAL_MCAST_LOGIC_REP_THRD, &logic_rep_threshold));

    /*reflective member only used for new added members,and can only be used in linked lists*/
    if(!DRV_FROM_TMM(lchip) &&
        ((SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID == p_mem_param->member_type) || (SYS_NH_PARAM_BRGMC_MEM_LOCAL == p_mem_param->member_type)
        || (SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH == p_mem_param->member_type)) &&
            !g_usw_nh_master[lchip]->reflective_brg_en && !p_mem_param->is_src_port_check_dis)
    {
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_get_port_reflect(lchip, p_mem_param));
    }
    if (MCHIP_NH(lchip)->analyze_member)
    {
        CTC_ERROR_RETURN(MCHIP_NH(lchip)->analyze_member(lchip, p_db_member_list, p_mem_param, (void*)&p_member_info, &entry_exist));
    }
    else
    {
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_analyze_member(lchip, p_db_member_list, p_mem_param, &p_member_info, &entry_exist, &repli_pos));
    }
   if(p_mem_param->member_type == SYS_NH_PARAM_BRGMC_MEM_BITMAP && p_member_info )
    {
       entry_exist = 0;
    }
    if (entry_exist)
    {
        return CTC_E_NONE;
    }

    if (p_member_info
        && (p_mem_param->member_type == SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP)
        && ((p_member_info->dsmet.replicate_num + 1) == SYS_NH_LOGICAL_REPLI_MAX_NUM))
    {
        p_member_info = NULL;
    }

    if (((!p_member_info) || CTC_FLAG_ISSET(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM))
        && ((p_info_mcast->physical_replication_num + p_mem_param->stk_rsv_mem) >= SYS_NH_PHY_REP_MAX_NUM))
    {
        return CTC_E_INVALID_PARAM;
    }

    if (NULL == p_member_info
        && p_mem_param->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_LOGIC_REP
        && ((p_info_mcast->physical_replication_num + 16) >= SYS_NH_PHY_REP_MAX_NUM))
    {
        return CTC_E_NH_EXCEED_MCAST_PHY_REP_NUM;
    }

    /*3. Op  DsNH*/
    CTC_ERROR_RETURN(_sys_usw_nh_mcast_get_nh_and_edit_data(lchip,
                         p_mem_param, p_member_info, &dsnh_offset, &use_dsnh8w));

    /*3. Op DsMet*/
    if (p_member_info)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "2. Update old met!!!!!!!!!!!!\n");

        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "\ndsnh_offset:%d use_dsnh8w:%d replicate_num:%d\n",
                       dsnh_offset, use_dsnh8w, p_member_info->dsmet.replicate_num);

        if (MCHIP_NH(lchip)->update_mcast_mem)
        {
            CTC_ERROR_RETURN(MCHIP_NH(lchip)->update_mcast_mem(lchip, p_mem_param, p_db_member_list, p_info_mcast, p_member_info, 1));
            return CTC_E_NONE;
        }

        if (CTC_FLAG_ISSET(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_EN))
        {
            ret = (_sys_usw_nh_mcast_update_logic_rep_list(lchip, p_member_info, p_mem_param->ref_nhid, 1));
            if (ret == CTC_E_NO_RESOURCE)
            {
                        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "logic no resource, switch to update phy list!!!,   nhid:%u. list cnt:%u\n",
        p_mem_param->ref_nhid, p_member_info->dsmet.replicate_num);
                /*have no logic rep resource*/
                p_mem_param->logic_rep_ability = 0;
                phy_list_en = 1;
            }
            else if (ret)
            {
                return ret;
            }
        }
        else if(p_mem_param->member_type == SYS_NH_PARAM_BRGMC_MEM_BITMAP)
        {
            uint32 actual_bpm[CTC_PORT_BITMAP_IN_WORD] ={0};
            int32 delta_count =0;
            uint8 loop =0;
            while (loop < (MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM)/32))
            {
                actual_bpm[loop] = (~(p_mem_param->pbm_hw[loop]))  & p_mem_param->pbm[loop];
                p_mem_param->pbm_hw[loop]  |= p_mem_param->pbm[loop];
                loop++;
            }
            CTC_BMP_COUNT_RANGE(actual_bpm, delta_count, 0, MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM));
            p_member_info->dsmet.replicate_num += delta_count;
            p_info_mcast->physical_replication_num += delta_count;

        }
        else if (CTC_FLAG_ISSET(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM))
        {
            uint8 port_type = 0;
            uint16 port_id = 0;
            SYS_MC_MAP_PBM_PORT_ID(p_mem_param->destid, port_type, port_id);
            p_member_info->dsmet.port_type = port_type;
            CTC_BMP_SET(p_mem_param->pbm_hw, port_id);
            if (p_mem_param->no_hw)
            {
                sys_nh_mcast_meminfo_param_t* mem_param = (sys_nh_mcast_meminfo_param_t*)p_member_info;
                CTC_BMP_SET(mem_param->member.pbm_hw, port_id); 
            }
            if (p_member_info->dsmet.ucastid != SYS_NH_MET_DROP_UCAST_ID)
            {
                p_member_info->dsmet.replicate_num += 1;
                p_info_mcast->physical_replication_num += 1;
            }
            p_member_info->dsmet.ucastid = 0;

        }
        else if ((SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP == p_mem_param->member_type)
            || (SYS_NH_PARAM_MCAST_MEM_LOCAL_LOGIC_REP == p_mem_param->member_type))
        {
            p_member_info->dsmet.replicate_num += 1;
        }
        else
        {
            return CTC_E_NONE;
        }

        p_member_info->dsmet.flag |= use_dsnh8w ? SYS_NH_DSMET_FLAG_USE_DSNH8W : 0;
        if (NULL == p_member_info->list_head.p_next
            && !CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_STK_MEM_PROFILE)
            && !CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE))
        {
            if ( p_info_mcast->profile_met_offset)
            {
                p_member_info->dsmet.next_dsmet_offset = p_info_mcast->profile_met_offset;
            }
            else
            {
                p_member_info->dsmet.next_dsmet_offset = SYS_NH_MET_END_REPLICATE_OFFSET;
            }
        }
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_write_dsmet(lchip, &p_member_info->dsmet, p_mem_param));
    }
    else if (p_mem_param->ref_list_cnt+1 >= logic_rep_threshold && logic_rep_threshold && p_mem_param->p_1st_node &&
       !CTC_FLAG_ISSET(((sys_nh_mcast_meminfo_t*)p_mem_param->p_1st_node)->dsmet.flag,  SYS_NH_DSMET_FLAG_LOGIC_REPLI_EN) &&
       CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_ABILITY))
    {
        sys_nh_mcast_meminfo_t met_info;
        sys_nh_mcast_dsmet_io_t dsmet_io;
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Switch to logic replicate!\n");
        /*encode dsmet info*/
        sal_memset(&met_info, 0, sizeof(sys_nh_mcast_meminfo_t));
        met_info.dsmet.entry_type = SYS_NH_ENTRY_TYPE_MET;
        met_info.dsmet.fid = p_mem_param->fid;
        met_info.dsmet.vid = p_mem_param->vid;
        met_info.dsmet.ucastid = p_mem_param->destid;
        met_info.dsmet.replicate_num  = 0;
        met_info.dsmet.dsnh_offset = dsnh_offset;
        if ((SYS_NH_PARAM_IPMC_MEM_LOCAL == p_mem_param->member_type && p_mem_param->l3if_type == CTC_L3IF_TYPE_VLAN_IF)
            || p_mem_param->is_mirror
            || SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID == p_mem_param->member_type)
        {
            met_info.dsmet.entry_type = SYS_NH_ENTRY_TYPE_MET_6W;
        }
        sal_memset(&dsmet_io, 0, sizeof(sys_nh_mcast_dsmet_io_t));
        dsmet_io.p_mem_param = p_mem_param;
        dsmet_io.dsnh_offset = dsnh_offset;
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_build_dsmet_info(lchip, p_info_mcast, &dsmet_io, &met_info.dsmet));

        /*Switch Physical replicate to Logic replicate*/
        ret = (_sys_usw_nh_mcast_rep_phy2logic(lchip, p_info_mcast, (sys_nh_mcast_meminfo_t*)p_mem_param->p_1st_node,
                &met_info, p_mem_param->ref_list_cnt+1));
        if (ret == CTC_E_NO_RESOURCE)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "logic no resource, switch to update phy list!!!,   nhid:%u. list cnt:%u\n",  p_mem_param->ref_nhid, p_mem_param->ref_list_cnt);
            /*have no logic rep resource*/
            phy_list_en = 1;
        }
        else if (ret)
        {
            return ret;
        }
    }
   else
   {
        phy_list_en = 1;
   }

   if (phy_list_en)
   {
       SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "1. First/New met!!!!!!!!!!!!\n");
       if (MCHIP_NH(lchip)->add_dsmet_entry)/*Arctic*/
       {
           ret = MCHIP_NH(lchip)->add_dsmet_entry(lchip, p_mem_param,
                                                  dsnh_offset,
                                                  use_dsnh8w,
                                                  p_db_member_list,
                                                  p_info_mcast);
       }
       else
       {
       ret = _sys_usw_nh_mcast_add_dsmet_entry(lchip, p_mem_param,
                                               dsnh_offset,
                                               use_dsnh8w,
                                               (p_mem_param->ref_list_cnt? p_mem_param->p_last_node : NULL),
                                               p_info_mcast);
       }
       if ((ret == CTC_E_NONE)
           && (SYS_NH_PARAM_BRGMC_MEM_BITMAP != p_mem_param->member_type))
       {
           p_info_mcast->physical_replication_num += 1;
       }
   }


    return ret;
}

STATIC int32
_sys_usw_nh_mcast_remove_member(uint8 lchip, sys_nh_param_mcast_member_t* p_mem_param,
                                      ctc_list_pointer_t* p_db_member_list,
                                      sys_nh_info_mcast_t* p_info_mcast)
{
    sys_nh_mcast_meminfo_t* p_member_info = NULL;
    bool entry_exist = FALSE;
    uint32 repli_pos = 0;
    uint8  logic_rep = 0;
    int32 delta_count =0;

    int32  ret   = 0;
    uint32 tmp_bpm[CTC_PORT_BITMAP_IN_WORD] ={0};

    /*1. Check if mcast member have been existed*/
    if (p_mem_param->is_linkagg &&
        (p_mem_param->destid > SYS_USW_MAX_LINKAGG_GROUP_NUM))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Linkagg] Tid is invalid \n");
			return CTC_E_BADID;

    }
    p_mem_param->is_del = 1;
    p_mem_param->is_mirror = CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_IS_MIRROR);
    logic_rep = CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_EN);
    if (p_mem_param->is_mirror
        && (p_mem_param->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH))
    {
        p_mem_param->member_type = SYS_NH_PARAM_MCAST_MEM_MIRROR_WITH_NH;
    }
    if ((p_mem_param->member_type == SYS_NH_PARAM_IPMC_MEM_LOCAL) && logic_rep && !p_mem_param->cvid)
    {
        p_mem_param->member_type = SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP;
    }

    if (p_mem_param->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH)
    {
        /*special for xgpon*/
        uint8 repli_en = 0;
        sys_usw_nh_is_logic_repli_en(lchip, p_mem_param->ref_nhid, &repli_en);
        if (repli_en && DRV_IS_DUET2(lchip))
        {
            p_mem_param->member_type = SYS_NH_PARAM_MCAST_MEM_LOCAL_LOGIC_REP;
        }
    }

    if (!p_mem_param->is_linkagg &&
        !p_mem_param->is_destmap_profile &&
        p_mem_param->member_type != SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE &&
        p_mem_param->member_type != SYS_NH_PARAM_MCAST_MEM_REMOTE)
    {
        p_mem_param->destid = SYS_MAP_SYS_LPORT_TO_DRV_LPORT(p_mem_param->destid);

        if ((p_mem_param->member_type == SYS_NH_PARAM_BRGMC_MEM_LOCAL ||
            p_mem_param->member_type == SYS_NH_PARAM_IPMC_MEM_LOCAL)
        && SYS_MC_DESTID_IS_INTERNAL(p_mem_param->destid))
        {
            return CTC_E_INVALID_PARAM;
        }
    }
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "p_mem_param->destid:0x%x\n", p_mem_param->destid);
    if(!DRV_FROM_TMM(lchip) &&
        ((SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID == p_mem_param->member_type) || (SYS_NH_PARAM_BRGMC_MEM_LOCAL == p_mem_param->member_type)
        || (SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH == p_mem_param->member_type)) &&
            !g_usw_nh_master[lchip]->reflective_brg_en && !p_mem_param->is_src_port_check_dis)
    {
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_get_port_reflect(lchip, p_mem_param));
    }

    p_mem_param->logic_rep_ability = 1;/*remove process, logic_rep_ability have no affect, just used to analyze member*/
    if (MCHIP_NH(lchip)->analyze_member)
    {
        CTC_ERROR_RETURN(MCHIP_NH(lchip)->analyze_member(lchip, p_db_member_list, p_mem_param, (void*)&p_member_info, &entry_exist));
    }
    else
    {
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_analyze_member(lchip, p_db_member_list, p_mem_param, &p_member_info, &entry_exist, &repli_pos));
    }
    p_mem_param->logic_rep_ability = 0;
    sal_memcpy(tmp_bpm, p_mem_param->pbm_hw, (MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM) >> 3));

    if ((p_mem_param->member_type == SYS_NH_PARAM_BRGMC_MEM_BITMAP) && (NULL == p_member_info))
    {
        return CTC_E_NONE;
    }
    if (!entry_exist || NULL == p_member_info)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Member not exist \n");
        return CTC_E_NOT_EXIST;
    }

    if(p_mem_param->member_type == SYS_NH_PARAM_BRGMC_MEM_BITMAP && p_member_info)
    {
        uint32 actual_bpm[CTC_PORT_BITMAP_IN_WORD] ={0};
        uint8 loop =0;
        while(loop < (MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM)/32))
        {
             actual_bpm[loop] = p_mem_param->pbm_hw[loop] & p_mem_param->pbm[loop];
             p_mem_param->pbm_hw[loop]  &= (~actual_bpm[loop]);
             loop++;
        }
        CTC_BMP_COUNT_RANGE(actual_bpm,delta_count, 0,MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM));

        if (!delta_count)
        {
            return CTC_E_NONE;
        }
    }

    CTC_ERROR_RETURN(_sys_usw_nh_mcast_free_nh_and_edit_data(lchip, p_member_info, repli_pos));

    if (CTC_FLAG_ISSET(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_EN))
    {
    /*Update Logic replicate list*/
        uint32 logic_rep_threshold = 0;
        uint16 replicate_num = p_member_info->dsmet.replicate_num;
        CTC_ERROR_RETURN(sys_usw_global_ctl_get(lchip, CTC_GLOBAL_MCAST_LOGIC_REP_THRD, &logic_rep_threshold));
        if (replicate_num <= logic_rep_threshold)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " Switch to physical, current list cnt:%u \n", p_member_info->dsmet.replicate_num);
            /*Switch Logiic replicate to Physical replicate*/
            ret = (_sys_usw_nh_mcast_rep_logic2phy(lchip, p_info_mcast, p_member_info, p_mem_param->ref_nhid, p_member_info->dsmet.replicate_num));
            if (ret && (ret != CTC_E_NO_RESOURCE))
            {
                return ret;
            }
        }

        if ((replicate_num > logic_rep_threshold) || (ret == CTC_E_NO_RESOURCE))
        {
            CTC_ERROR_RETURN(_sys_usw_nh_mcast_update_logic_rep_list(lchip, p_member_info,p_mem_param->ref_nhid, 0));
        }
        return CTC_E_NONE;
    }

    if (p_member_info->dsmet.replicate_num == 0)
    {
        /*Remove member node*/
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_del_dsmet_entry(lchip, p_mem_param,
                                                                  p_member_info,
                                                                  p_db_member_list,
                                                                  p_info_mcast));

        if (p_info_mcast->physical_replication_num != 0)
        {
            p_info_mcast->physical_replication_num -= 1;
        }
    }
    else
    {
        if (MCHIP_NH(lchip)->update_mcast_mem)
        {
            sal_memcpy(p_mem_param->pbm_hw, tmp_bpm, (MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM) >> 3));
            CTC_ERROR_RETURN(MCHIP_NH(lchip)->update_mcast_mem(lchip, p_mem_param, p_db_member_list, p_info_mcast, p_member_info, 0));
            return CTC_E_NONE;
        }

        if (p_mem_param->member_type == SYS_NH_PARAM_BRGMC_MEM_BITMAP)
        {
            p_info_mcast->physical_replication_num -= delta_count;
            if (p_member_info->dsmet.replicate_num >= delta_count)
            {
                p_member_info->dsmet.replicate_num -= delta_count;
            }
            else
            {
                /*Remove member node*/
                CTC_ERROR_RETURN(_sys_usw_nh_mcast_del_dsmet_entry(lchip, p_mem_param,
                                                                   p_member_info,
                                                                   p_db_member_list,
                                                                   p_info_mcast));
                return CTC_E_NONE;
            }
        }
        else  if (CTC_FLAG_ISSET(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM))
        {
            uint16 port_id = 0;
            port_id = SYS_MC_MAP_PORT_ID(p_mem_param->destid);
            CTC_BMP_UNSET(p_mem_param->pbm_hw, port_id);
            p_member_info->dsmet.replicate_num -= 1;
            p_info_mcast->physical_replication_num -= 1;
        }
        else if ((SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP == p_mem_param->member_type)
            || (SYS_NH_PARAM_MCAST_MEM_LOCAL_LOGIC_REP == p_mem_param->member_type))
        {
            p_member_info->dsmet.replicate_num -= 1;
        }

        if (NULL == p_member_info->list_head.p_next
            && !CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_STK_MEM_PROFILE)
        && !CTC_FLAG_ISSET(p_info_mcast->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE))
        {
            if ( p_info_mcast->profile_met_offset)
            {
                p_member_info->dsmet.next_dsmet_offset = p_info_mcast->profile_met_offset;
            }
            else
            {
                p_member_info->dsmet.next_dsmet_offset = SYS_NH_MET_END_REPLICATE_OFFSET;
            }
        }
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_write_dsmet(lchip, &p_member_info->dsmet, p_mem_param));
    }
    return CTC_E_NONE;
}


STATIC int32
_sys_usw_nh_mcast_update_member(uint8 lchip, uint32 basic_met_offset,
                                   sys_nh_param_mcast_member_t* p_mem_param,
                                   ctc_list_pointer_t* p_db_member_list,
                                   sys_nh_info_mcast_t* p_info_mcast)
{
    sys_nh_mcast_meminfo_t* p_member_info = NULL;
    bool entry_exist = FALSE;
    uint32 repli_pos = 0;
    int32 ret = 0;

    /*1. Check if mcast member have been existed*/
    CTC_PTR_VALID_CHECK(p_mem_param);
    CTC_ERROR_RETURN(_sys_usw_nh_mcast_analyze_member(lchip, p_db_member_list,
                                                            p_mem_param, &p_member_info,
                                                            &entry_exist, &repli_pos));
    if ((NULL == p_member_info) || (!entry_exist))
    {
        return CTC_E_NOT_EXIST;
    }

    if(p_mem_param->logic_port_type_en)
    {
        if (p_mem_param->is_horizon_split)
        {
            CTC_SET_FLAG(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_HORIZON_SPLIT_EN);
        }
        else
        {
            CTC_UNSET_FLAG(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_HORIZON_SPLIT_EN);
        }
    }

    /*3. Op DsMet*/
    CTC_ERROR_RETURN(_sys_usw_nh_mcast_write_dsmet(lchip, &p_member_info->dsmet, p_mem_param));

    return ret;
}

STATIC int32
_sys_usw_nh_mcast_update_grp(uint8 lchip, sys_nh_param_mcast_member_t* p_mem_param,
                                   sys_nh_info_mcast_t* p_mcast_db)
{
    ctc_list_pointer_t* p_db_member_list = NULL;
    sys_nh_mcast_meminfo_t* p_meminfo = NULL;
    ctc_list_pointer_node_t* p_pos_mem = NULL;
    sys_nh_info_dsmet_t * p_dsmet = NULL;
    uint16 old_flag = 0;
    sys_met_t dsmet;
    
    p_db_member_list = &(p_mcast_db->p_mem_list);
    CTC_LIST_POINTER_LOOP(p_pos_mem, p_db_member_list)
    {
        p_meminfo = _ctc_container_of(p_pos_mem, sys_nh_mcast_meminfo_t, list_head);
        if (NULL == p_meminfo)
        {
            break;
        }
        p_dsmet = &(p_meminfo->dsmet);
        if ((p_dsmet->member_type == SYS_NH_PARAM_BRGMC_MEM_LOCAL)
            || (p_dsmet->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH)
            || (p_dsmet->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID)
            || (p_dsmet->member_type == SYS_NH_PARAM_BRGMC_MEM_BITMAP))
        {
            old_flag = p_dsmet->flag;
            if (p_mem_param->is_src_port_check_dis)
            {
                CTC_UNSET_FLAG(p_dsmet->flag, SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD); 
            }
            else
            {
                CTC_SET_FLAG(p_dsmet->flag, SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD);
            }
            
            sal_memset(&dsmet, 0, sizeof(dsmet));
            CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, p_meminfo->dsmet.entry_type, p_meminfo->dsmet.dsmet_offset, &dsmet));
            sal_memcpy(p_mem_param->pbm_hw, dsmet.port_bitmap, (MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM) >> 3));
            CTC_ERROR_RETURN(_sys_usw_nh_mcast_write_dsmet(lchip, p_dsmet, p_mem_param));
            p_dsmet->flag = old_flag;
        }
    }

    if (p_mem_param->is_src_port_check_dis)
    {
        CTC_SET_FLAG(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_SRC_CHK_DISABLE);
    }
    else
    {
        CTC_UNSET_FLAG(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_SRC_CHK_DISABLE);
    }

    return CTC_E_NONE;
}


STATIC int32
_sys_usw_nh_mcast_add_dsfwd(uint8 lchip, sys_nh_info_com_t* p_com_db, uint8 is_6w, uint8 is_dsfwd1)
{
    sys_nh_info_mcast_t* p_nh_info = NULL;
    sys_nh_param_dsfwd_t dsfwd_param;

    p_nh_info     = (sys_nh_info_mcast_t*)(p_com_db);
    sal_memset(&dsfwd_param, 0, sizeof(sys_nh_param_dsfwd_t));
    sys_usw_get_gchip_id(lchip, & dsfwd_param.dest_chipid);
    dsfwd_param.drop_pkt = FALSE;
    dsfwd_param.dest_id = (p_nh_info->basic_met_offset >> g_usw_nh_master[lchip]->met_mode);
    dsfwd_param.is_mcast = TRUE;
    dsfwd_param.dsfwd_offset = p_nh_info->hdr.dsfwd_offset;
    dsfwd_param.dsnh_offset = 0;
    dsfwd_param.stats_ptr = p_nh_info->stats_ptr;
    dsfwd_param.is_6w = is_6w;


    CTC_ERROR_RETURN(_sys_usw_nh_add_dsfwd(lchip, p_com_db, &dsfwd_param, is_dsfwd1));
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_INFO_MCAST, 1);

    return CTC_E_NONE;
}


STATIC int32
_sys_usw_nh_mcast_map_member_info(uint8 lchip, ctc_mcast_nh_param_member_t * p_member_info,
                                         sys_nh_info_dsmet_t * p_dsmet, ctc_nh_info_t* p_nh_info,
                                         uint32 * p_valid_cnt, uint32 * p_member_idx, uint16 vid_index)
{
    uint8 gchip = 0;
    uint8 is_linkagg = 0;

    switch (p_dsmet->member_type)
    {
        case SYS_NH_PARAM_BRGMC_MEM_LOCAL:
        case SYS_NH_PARAM_BRGMC_MEM_BITMAP:
        case SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE:
        case SYS_NH_PARAM_BRGMC_MEM_RAPS:
        case SYS_NH_PARAM_MCAST_MEM_MIRROR_WITH_NH:
            p_member_info->member_type = CTC_NH_PARAM_MEM_BRGMC_LOCAL;
            break;
        case SYS_NH_PARAM_IPMC_MEM_LOCAL:
        case SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP:
        case SYS_NH_PARAM_IPMC_MEM_LOOP_BACK:
            p_member_info->member_type = CTC_NH_PARAM_MEM_IPMC_LOCAL;
            break;
        case SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH:
        case SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID:
            p_member_info->member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
            p_member_info->ref_nhid    = p_dsmet->ref_nhid;
            break;
        case SYS_NH_PARAM_MCAST_MEM_REMOTE:
            p_member_info->member_type = CTC_NH_PARAM_MEM_REMOTE;
            break;
        default:
            p_member_info->member_type = CTC_NH_PARAM_MEM_INVALID;
            break;
    }


    is_linkagg = CTC_FLAG_ISSET(p_dsmet->flag, SYS_NH_DSMET_FLAG_IS_LINKAGG);
    if (is_linkagg)
    {
        gchip = 0x1F;
    }
    else
    {
        sys_usw_get_gchip_id(lchip, &gchip);
    }
    p_member_info->gchip_id = gchip;
    p_member_info->is_source_check_dis = !CTC_FLAG_ISSET(p_dsmet->flag, SYS_NH_DSMET_FLAG_PORT_CHK_DISCARD)? 1 : 0;
    if(CTC_FLAG_ISSET(p_dsmet->flag, SYS_NH_DSMET_FLAG_HORIZON_SPLIT_EN))
    {
       p_member_info->logic_port_type = 1;
       CTC_SET_FLAG(p_member_info->flag , CTC_MCAST_NH_FLAG_LOGIC_PORT_TYPE_EN);
    }

    if ((SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP == p_dsmet->member_type)&&(p_dsmet->replicate_num))
    {
        p_member_info->vid = p_dsmet->vid_list[vid_index];
    }
    else
    {
        p_member_info->vid = p_dsmet->vid;
        p_member_info->cvid = p_dsmet->cvid;
    }


    p_member_info->is_reflective = CTC_FLAG_ISSET(p_dsmet->flag, SYS_NH_DSMET_FLAG_REFECTIVE);
    p_member_info->destid = CTC_MAP_LPORT_TO_GPORT(gchip, p_dsmet->ucastid);

    if (CTC_FLAG_ISSET(p_dsmet->flag, SYS_NH_DSMET_FLAG_USE_PBM))
    {
        sys_met_t dsmet;
        sal_memset(&dsmet, 0, sizeof(dsmet));
        CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, p_dsmet->entry_type, p_dsmet->dsmet_offset, &dsmet));

        if(!DRV_FROM_AT(lchip))
        {
            if (0 == p_dsmet->port_type)
            {
                p_member_info->port_bmp[0] = dsmet.port_bitmap[0];
                p_member_info->port_bmp[1] = dsmet.port_bitmap[1];
            }
            else
            {
                p_member_info->port_bmp[2] = dsmet.port_bitmap[0];
                p_member_info->port_bmp[3] = dsmet.port_bitmap[1];
            }
        }
        p_member_info->port_bmp_en = 1;
    }

    if (CTC_NH_PARAM_MEM_IPMC_LOCAL == p_member_info->member_type)
    {
        if ((p_member_info->port_bmp_en)||(SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP == p_dsmet->member_type))
        {
            p_member_info->l3if_type = CTC_L3IF_TYPE_VLAN_IF;
        }
        else if (p_dsmet->vid)
        {
            sys_l3if_prop_t l3if_prop;
            CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_info_with_port_and_vlan(lchip, p_dsmet->ucastid, p_dsmet->vid, p_dsmet->cvid, &l3if_prop));
            p_member_info->l3if_type = l3if_prop.l3if_type;
        }
        else
        {
            p_member_info->l3if_type = CTC_L3IF_TYPE_PHY_IF;
        }
    }

    return CTC_E_NONE;

}
STATIC INLINE int32
_sys_usw_nh_mcast_bind_group(uint8 lchip, sys_nh_info_mcast_t* p_mcast_db, uint32 group_id)
{
    uint32 cmd        = 0;
    DsFwd_m dsfwd;
    DsFwdHalf_m dsfwd_half;
    uint32 mcast_nhid;
    sys_nh_info_com_t* p_bind_mcast_info = NULL;
    uint32 dsfwd_offset = 0;
    uint32 tbl_id = DsFwd_t;

    sal_memset(&dsfwd_half, 0, sizeof(dsfwd_half));
    CTC_ERROR_RETURN(_sys_usw_nh_get_mcast_nh(lchip, group_id, &mcast_nhid, (void **)&p_bind_mcast_info));
    dsfwd_offset = p_bind_mcast_info->hdr.dsfwd_offset;
    if(p_bind_mcast_info->hdr.dsfwd_offset)
    {
        cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, dsfwd_offset>>1, cmd, &dsfwd));
        if(dsfwd_offset & 0x1)
        {
            GetDsFwdDualHalf(A, g_1_dsFwdHalf_f,   &dsfwd,   &dsfwd_half);
        }
        else if(GetDsFwd(V, isHalf_f, &dsfwd))
        {
            GetDsFwdDualHalf(A, g_0_dsFwdHalf_f,   &dsfwd,   &dsfwd_half);
        }
    }
    else
    {
        SetDsFwdHalf(V, destMap_f, &dsfwd_half, SYS_ENCODE_MCAST_IPE_DESTMAP(group_id));
        SetDsFwdHalf(V, nextHopPtr_f, &dsfwd_half, p_bind_mcast_info->hdr.dsnh_offset);
        SetDsFwdHalf(V, isHalf_f, &dsfwd_half, 1);
    }

    if ((CTC_FLAG_ISSET(p_mcast_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD))
        && !CTC_FLAG_ISSET(p_mcast_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_DSFWD_IS_6W))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Can't support default entry's group with dsfwd half, bind mcast group must use 2 sequential dsfwd half\n");
        return CTC_E_INVALID_PARAM;
    }
    else if (!CTC_FLAG_ISSET(p_mcast_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD))
    {
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_add_dsfwd(lchip, (sys_nh_info_com_t*)p_mcast_db, 1, 0));
    }

    dsfwd_offset = p_mcast_db->hdr.dsfwd_offset;
    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, dsfwd_offset >> 1, cmd, &dsfwd));
    SetDsFwd(V, isHalf_f, &dsfwd, 1);
    SetDsFwdDualHalf(A, g_1_dsFwdHalf_f,   &dsfwd,   &dsfwd_half);
    cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, dsfwd_offset >> 1, cmd, &dsfwd));
    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_mcast_del_logic_rep_list(uint8 lchip, sys_nh_info_mcast_t* p_nh_info)/*For TMM*/
{
    sys_nh_info_mcast_t* p_mcast_db = p_nh_info;
    ctc_list_pointer_node_t* p_pos = NULL, * p_pos_next = NULL;
    sys_nh_mcast_meminfo_t* p_member = NULL;

    CTC_LIST_POINTER_LOOP_DEL(p_pos, p_pos_next, &(p_mcast_db->p_mem_list))
    {
        p_member = _ctc_container_of(p_pos, sys_nh_mcast_meminfo_t, list_head);
        sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_LOGIC_REP, 1, p_member->dsmet.dsmet_offset);
        mem_free(p_member);
    }
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MCAST_MEM, 1);

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_remove_all_members(uint8 lchip, sys_nh_info_mcast_t* p_mcast_db)
{
    ctc_list_pointer_node_t* p_pos = NULL, * p_pos_next = NULL;
    sys_nh_mcast_meminfo_t* p_member = NULL;
    uint8 met_num = 1;

    _sys_usw_nh_mcast_entry_set_default(lchip, p_mcast_db,  p_mcast_db->basic_met_offset, FALSE, TRUE);
    CTC_LIST_POINTER_LOOP_DEL(p_pos, p_pos_next, &(p_mcast_db->p_mem_list))
    {
        p_member = _ctc_container_of(p_pos, sys_nh_mcast_meminfo_t, list_head);
        if (p_mcast_db->basic_met_offset != p_member->dsmet.dsmet_offset)
        {
            if (CTC_FLAG_ISSET(p_member->dsmet.flag, SYS_NH_DSMET_FLAG_IS_MCAST_APS) && !CTC_FLAG_ISSET(p_member->dsmet.flag, SYS_NH_DSMET_FLAG_IS_BASIC_MET))
            {
                met_num = 2;
            }
            sys_usw_nh_offset_free(lchip, p_member->dsmet.entry_type, met_num, p_member->dsmet.dsmet_offset);
        }


        if (SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP == p_member->dsmet.member_type)
        {
            uint8 entry_num = 0;

            if (p_member->dsmet.vid_list)
            {
                mem_free(p_member->dsmet.vid_list);
                entry_num = (p_member->dsmet.replicate_num / SYS_NH_MCAST_REPLI_INCR_STEP + 1)*SYS_NH_MCAST_REPLI_INCR_STEP;
            }
            else
            {
                entry_num = 1;
            }

            sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_NEXTHOP_4W, entry_num, p_member->dsmet.dsnh_offset);
        }

        if (CTC_FLAG_ISSET(p_member->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_EN))
        {
            ctc_list_pointer_node_t* p_logic_pos, * p_logic_next;
            sys_nh_mcast_meminfo_t* logic_rep_node = NULL;
            CTC_LIST_POINTER_LOOP_DEL(p_logic_pos, p_logic_next, &p_member->dsmet.logic_rep_list)
            {
                logic_rep_node = _ctc_container_of(p_logic_pos, sys_nh_mcast_meminfo_t, list_head);
                sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_LOGIC_REP, 1, logic_rep_node->dsmet.dsmet_offset);
                /*delete node from logic replicate list*/
                ctc_list_pointer_delete(&p_member->dsmet.logic_rep_list, &(p_member->list_head));
                mem_free(logic_rep_node);
            }
        }
        ctc_list_pointer_delete(&p_mcast_db->p_mem_list, p_pos);
        mem_free(p_member);
    }


    return CTC_E_NONE;
}


int32
sys_usw_nh_get_mcast_member_info(uint8 lchip, sys_nh_info_mcast_t* p_mcast_db, ctc_nh_info_t* p_nh_info)
{
    ctc_list_pointer_t* p_db_member_list = NULL;
    sys_nh_mcast_meminfo_t* p_meminfo = NULL;
    ctc_list_pointer_node_t* p_pos_mem = NULL;
    sys_nh_info_dsmet_t * p_dsmet = NULL;
    ctc_mcast_nh_param_member_t * p_member_info = NULL;
    uint32 valid_cnt = 0;
    uint32 member_idx = 0;
    int32 ret = CTC_E_NONE;
    uint8 not_end = 0;
    uint16 vid_index = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "\n%s()\n", __FUNCTION__);
    if (0 == p_nh_info->buffer_len)
    {
        return CTC_E_INVALID_PARAM;
    }

    p_nh_info->valid_number = 0;
    p_member_info = p_nh_info->buffer;
    member_idx = 0;
    valid_cnt = 0;

    p_db_member_list = &(p_mcast_db->p_mem_list);
    CTC_LIST_POINTER_LOOP(p_pos_mem, p_db_member_list)
    {
        p_meminfo = _ctc_container_of(p_pos_mem, sys_nh_mcast_meminfo_t, list_head);
        if (NULL == p_meminfo)
        {
            break;
        }
        p_dsmet = &(p_meminfo->dsmet);
        if ((SYS_NH_PARAM_IPMC_MEM_LOCAL_LOGIC_REP == p_dsmet->member_type)
            &&(p_dsmet->replicate_num))
        {
            for (vid_index = 0; vid_index <= p_dsmet->replicate_num; vid_index++)
            {
                member_idx++;
                if (member_idx <= p_nh_info->start_index)
                {
                    continue;
                }

                ret = _sys_usw_nh_mcast_map_member_info(lchip, p_member_info, p_dsmet, p_nh_info,
                                                               &valid_cnt, &member_idx, vid_index);
                if (CTC_E_NONE != ret)
                {
                    not_end = 1;
                    goto end;
                }
                valid_cnt++;
                if (p_nh_info->buffer_len <= valid_cnt)
                {
                    not_end = 1;
                    goto end;
                }
                p_member_info++;
            }
        }
        else if (CTC_FLAG_ISSET(p_meminfo->dsmet.flag, SYS_NH_DSMET_FLAG_LOGIC_REPLI_EN))
        {
            sys_nh_mcast_meminfo_t* logic_rep_node = NULL;
            ctc_list_pointer_node_t* p_logic_pos = NULL;
            uint16 loop = 0;
            p_logic_pos = ctc_list_pointer_head(&p_meminfo->dsmet.logic_rep_list);
            for (loop = 0; loop < p_meminfo->dsmet.replicate_num ; loop ++)
            {
                logic_rep_node = _ctc_container_of(p_logic_pos, sys_nh_mcast_meminfo_t, list_head);
                member_idx++;
                if (member_idx <= p_nh_info->start_index)
                {
                    p_logic_pos = ctc_list_pointer_next(p_logic_pos);
                    continue;
                }

                ret = _sys_usw_nh_mcast_map_member_info(lchip, p_member_info, &(logic_rep_node->dsmet), p_nh_info,
                                                        &valid_cnt, &member_idx, vid_index);
                if (CTC_E_NONE != ret)
                {
                    not_end = 1;
                    goto end;
                }
                valid_cnt++;
                if (p_nh_info->buffer_len <= valid_cnt)
                {
                    not_end = 1;
                    goto end;
                }
                p_member_info++;
                p_logic_pos = ctc_list_pointer_next(p_logic_pos);
            }
        }
        else
        {
            member_idx++;
            if (member_idx <= p_nh_info->start_index)
            {
                continue;
            }

            ret = _sys_usw_nh_mcast_map_member_info(lchip, p_member_info, p_dsmet, p_nh_info,
                                                           &valid_cnt, &member_idx, 0);
            if(CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_SRC_CHK_DISABLE))
            {
                p_member_info->is_source_check_dis = 1;
            }
            if (CTC_E_NONE != ret)
            {
                not_end = 1;
                break;
            }
            valid_cnt++;
            if (p_nh_info->buffer_len <= valid_cnt)
            {
                not_end = 1;
                break;
            }
            p_member_info++;
        }
    }

end:
    p_nh_info->next_query_index += valid_cnt;
    if (!not_end)
    {
        if (CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_STK_MEM_PROFILE))
        {
            valid_cnt++;
            p_member_info->member_type = CTC_NH_PARAM_MEM_REMOTE;
            p_member_info->destid = p_mcast_db->profile_nh_id;
        }
        else if (CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE))
        {
            valid_cnt++;
            p_member_info->member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
            p_member_info->ref_nhid = p_mcast_db->profile_nh_id;
        }

        p_nh_info->is_end = 1;
        p_nh_info->next_query_index = 0;
    }
    else if ((!(CTC_FLAG_ISSET(p_mcast_db->mcast_flag , SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_EN)
        || CTC_FLAG_ISSET(p_mcast_db->mcast_flag , SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_LIST_EN)
        || CTC_FLAG_ISSET(p_mcast_db->mcast_flag , SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_ABILITY))) &&
        (p_nh_info->next_query_index >= p_mcast_db->physical_replication_num))
    {
        p_nh_info->is_end = 1;
    }
    p_nh_info->valid_number = valid_cnt;

    return CTC_E_NONE;
}


int32
sys_usw_nh_create_mcast_cb(uint8 lchip, sys_nh_param_com_t* p_com_nh_para,
                                 sys_nh_info_com_t* p_com_db)
{
    sys_nh_param_mcast_t* p_nh_para_mcast = (sys_nh_param_mcast_t*)p_com_nh_para;
    sys_nh_info_mcast_t* p_mcast_db = (sys_nh_info_mcast_t*)p_com_db;
    int32 ret = 0;
    uint8 first_met_multi = 1;
    uint32 new_offset = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    /* 1. sanity check & init */
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhType = %u, NHID = %u, isInternaNH = %u, \n\
        GroupId = %d, Opcode = %d\n",
                   p_nh_para_mcast->hdr.nh_param_type,
                   p_nh_para_mcast->hdr.nhid,
                   p_nh_para_mcast->hdr.is_internal_nh,
                   p_nh_para_mcast->groupid,
                   p_nh_para_mcast->opcode);

    /*2. Malloc and init DB structure*/
    first_met_multi = 1 << g_usw_nh_master[lchip]->met_mode;
    if (CTC_FLAG_ISSET(p_nh_para_mcast->flag, CTC_NH_MCAST_FLAG_2X_GRP_ID))
    {
        first_met_multi = 2;
        CTC_SET_FLAG(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_2X_GRP_ID);
    }
    p_mcast_db->hdr.nh_entry_type = SYS_NH_TYPE_MCAST;
    p_mcast_db->basic_met_offset = p_nh_para_mcast->groupid << g_usw_nh_master[lchip]->met_mode;
    p_mcast_db->mcast_flag |= p_nh_para_mcast->is_mirror?SYS_NH_INFO_MCAST_FLAG_IS_MIRROR:0;
    p_mcast_db->hdr.nh_id = p_nh_para_mcast->hdr.nhid;

    if (CTC_FLAG_ISSET(p_nh_para_mcast->flag, CTC_NH_MCAST_FLAG_LOGIC_REP) && (!DRV_FROM_TMM(lchip) || p_nh_para_mcast->is_mcast_profile))
    {
        if (DRV_FROM_AT(lchip))
        {
            return CTC_E_NOT_SUPPORT;
        }
        CTC_SET_FLAG(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_LIST_EN);
        return CTC_E_NONE;
    }

    ctc_list_pointer_init(&(p_mcast_db->p_mem_list));
    if (!p_nh_para_mcast->is_mcast_profile)
    {
        /*mcast profile do not using global met resource*/
        CTC_ERROR_RETURN(_sys_usw_nh_check_glb_met_offset(lchip, p_mcast_db->basic_met_offset, first_met_multi, TRUE));
    }
    else
    {
        CTC_SET_FLAG(p_mcast_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_MCAST_PROFILE);
        CTC_ERROR_RETURN(sys_usw_nh_offset_alloc(lchip, (CTC_FLAG_ISSET(p_nh_para_mcast->flag, CTC_NH_MCAST_FLAG_2X_GRP_ID))? SYS_NH_ENTRY_TYPE_MET_6W : SYS_NH_ENTRY_TYPE_MET, 1, &new_offset));
        p_mcast_db->basic_met_offset = new_offset;
        new_offset = 0;
    }
    p_mcast_db->profile_met_offset = p_nh_para_mcast->profile_met_offset;
    /*Init basic dsmet entry*/
    CTC_ERROR_RETURN(_sys_usw_nh_mcast_entry_set_default(lchip,
                                                           p_mcast_db,
                                                           p_mcast_db->basic_met_offset,
                                                           TRUE,
                                                           TRUE));
    if (!p_nh_para_mcast->is_mcast_profile)
    {
        /*mcast profile do not using global met resource*/
        CTC_ERROR_RETURN(_sys_usw_nh_set_glb_met_offset(lchip, p_mcast_db->basic_met_offset, first_met_multi, TRUE));
        CTC_ERROR_GOTO(sys_usw_nh_add_mcast_db(lchip, p_nh_para_mcast->groupid, p_mcast_db), ret, error1);

    }

    if (TRUE == _sys_usw_nh_is_ipmc_logic_rep_enable(lchip) && !DRV_FROM_TMM(lchip))
    {
        CTC_SET_FLAG(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_EN);
    }

    if (CTC_FLAG_ISSET(p_nh_para_mcast->flag, CTC_NH_MCAST_FLAG_LOGIC_REP) && DRV_FROM_TMM(lchip))
    {
        CTC_SET_FLAG(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_ABILITY);
    }

    if (p_nh_para_mcast->is_mcast_profile)
    {
       return CTC_E_NONE;
    }

    if (p_nh_para_mcast->hdr.stats_valid)
    {
        CTC_ERROR_GOTO(sys_usw_flow_stats_get_statsptr(lchip,
                                                           p_nh_para_mcast->hdr.stats_id,
                                                           &p_nh_para_mcast->hdr.stats_ptr), ret, error2);

        p_mcast_db->stats_ptr = p_nh_para_mcast->hdr.stats_ptr;
        p_mcast_db->hdr.dsnh_offset = p_nh_para_mcast->hdr.stats_ptr;
    }
    if(p_nh_para_mcast->hdr.have_dsfwd)
    {
        CTC_ERROR_GOTO(_sys_usw_nh_mcast_add_dsfwd(lchip, p_com_db, 0, 0), ret, error2);
    }

    return CTC_E_NONE;

    error2:

    CTC_UNSET_FLAG(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_EN);

    if (!p_nh_para_mcast->is_mcast_profile)
    {
        sys_usw_nh_del_mcast_db(lchip, p_nh_para_mcast->groupid);
    }

    error1:
    if (!p_nh_para_mcast->is_mcast_profile)
    {
        _sys_usw_nh_set_glb_met_offset(lchip, p_mcast_db->basic_met_offset, first_met_multi, FALSE);
    }

    return ret;
}

/**
 @brief Callback function to delete multicast bridge nexthop

 @param[in] p_data, pointer used to store nexthop data

 @return CTC_E_XXX
 */
int32
sys_usw_nh_delete_mcast_cb(uint8 lchip, sys_nh_info_com_t* p_data, sys_nh_param_com_t* p_para)
{
    sys_nh_info_mcast_t* p_mcast_db = (sys_nh_info_mcast_t*)(p_data);
    uint8 first_met_multi = 1;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    if (p_mcast_db->pp_bmp != 0)
    {
        /* [AT] For pp mode, delete mcast nhp when last pp remove mcast group */
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Mcast nexthop pp bitmap is not 0, cannot delete\n");
        return CTC_E_IN_USE;
    }

    if (CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_LIST_EN))
    {
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_del_logic_rep_list(lchip, p_mcast_db));
        return CTC_E_NONE;
    }

    first_met_multi = 1 << g_usw_nh_master[lchip]->met_mode;
    if (CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_2X_GRP_ID))
    {
        first_met_multi = 2;
    }

    if (CTC_FLAG_ISSET(p_mcast_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_MCAST_PROFILE))
    {
        if (p_mcast_db->profile_ref_cnt)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Mcast Profile have been in use, cannot delete\n");
            return CTC_E_IN_USE;
        }
    }

    /*Free basic met offset*/
    p_mcast_db->profile_met_offset = 0;
    _sys_usw_nh_remove_all_members(lchip, p_mcast_db);
    _sys_usw_nh_remove_dsfwd(lchip, p_data);

    if(CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE))
    {
      sys_nh_info_mcast_t *p_mcast_profile_db;
      CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_mcast_db->profile_nh_id, (sys_nh_info_com_t**)&p_mcast_profile_db));
      if(p_mcast_profile_db && p_mcast_profile_db->profile_ref_cnt)
      {
        p_mcast_profile_db->profile_ref_cnt--;
      }
    }

    if (!CTC_FLAG_ISSET(p_mcast_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_MCAST_PROFILE))
    {
        _sys_usw_nh_set_glb_met_offset(lchip, p_mcast_db->basic_met_offset, first_met_multi, FALSE);
        sys_usw_nh_del_mcast_db(lchip, p_mcast_db->basic_met_offset >> g_usw_nh_master[lchip]->met_mode);
    }
    else
    {

        sys_usw_nh_offset_free(lchip, (CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_2X_GRP_ID))? SYS_NH_ENTRY_TYPE_MET_6W : SYS_NH_ENTRY_TYPE_MET, 1, p_mcast_db->basic_met_offset);

    }

    return CTC_E_NONE;
}
int32
_sys_usw_nh_update_mcast_member_profile(uint8 lchip, sys_nh_info_mcast_t* p_mcast_db,
                                         sys_nh_param_mcast_member_t* p_member, uint8 is_add)
{

    sys_nh_info_mcast_t* p_mcast_profile_db       = NULL;
    uint32 first_met_offset = 0;
    uint8 stk_member_list = p_member->member_type == SYS_NH_PARAM_MCAST_MEM_REMOTE;
    uint8 xgpon_en = 0;
    int32 ret = CTC_E_NONE;
    uint32 old_nhid = 0;

    if (is_add )
    {
#if 0
        if ((stk_member_list && CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE)) ||
            (CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_STK_MEM_PROFILE) && !stk_member_list))
        {
            return CTC_E_INVALID_CONFIG;
        }
#endif
    }
    else
    {
        if ( stk_member_list && !CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_STK_MEM_PROFILE))
        {
            return CTC_E_INVALID_CONFIG;
        }
        else if(!stk_member_list &&!CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE))
        {
            return CTC_E_INVALID_CONFIG;
        }
    }

    if (CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE))
    {
        old_nhid = p_mcast_db->profile_nh_id;
    }

    if (stk_member_list)
    {
        sys_usw_global_get_xgpon_en(lchip, &xgpon_en);
        if (xgpon_en)
        {
            p_mcast_db->profile_met_offset = p_member->destid;
        }
        else
        {
            if (!is_add && (p_member->destid != p_mcast_db->profile_nh_id))
            {
                return CTC_E_NOT_EXIST;
            }
            SYS_NH_UNLOCK;
            if (is_add)
            {
                if (SYS_CB_PTR(SYS_CB_STK_GET_MCAST_PROFILE_MET_OFFSET))
                {
                    ret = SYS_CB(SYS_CB_STK_GET_MCAST_PROFILE_MET_OFFSET, lchip, p_member->destid, &first_met_offset);
                }
                else
                {
                    SYS_NH_LOCK;
                    return CTC_E_NOT_EXIST;
                }
            }
            else
            {
                first_met_offset = p_mcast_db->profile_met_offset;
            }
            SYS_NH_LOCK;
            CTC_ERROR_RETURN(ret);
            p_mcast_db->profile_met_offset = first_met_offset;
        }
        p_mcast_db->profile_nh_id = p_member->destid;
    }
    else
    {
        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip,   p_member->ref_nhid, (sys_nh_info_com_t**)&p_mcast_profile_db));
        if (!p_mcast_profile_db && is_add)
        {
            return CTC_E_NOT_EXIST;
        }

        if (CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE) )
        {
            if(!is_add && p_member->ref_nhid != p_mcast_db->profile_nh_id)
            {
              return CTC_E_NOT_EXIST;
            }
#if 0
            if(is_add)
            {
               if (p_mcast_profile_db->basic_met_offset == p_mcast_db->profile_met_offset)
               {
                   return CTC_E_NONE;
               }
               else
               {
                   old_nhid = p_mcast_db->profile_nh_id;
               }
            }
#endif
        }
        p_mcast_db->profile_met_offset = is_add?p_mcast_profile_db->basic_met_offset:0;
        p_mcast_db->profile_nh_id = p_member->ref_nhid;

    }

    if (!is_add)
    {
        uint32 profile_met_offset = 0;
        SYS_NH_UNLOCK;
        if (SYS_CB_PTR(SYS_CB_STK_GET_MCAST_PROFILE_MET_OFFSET))
        {
            ret = SYS_CB(SYS_CB_STK_GET_MCAST_PROFILE_MET_OFFSET, lchip, 0, &profile_met_offset);
        }
        else
        {
            SYS_NH_LOCK;
            return CTC_E_NOT_EXIST;
        }
        p_mcast_db->profile_met_offset = profile_met_offset;
        SYS_NH_LOCK;
        CTC_ERROR_RETURN(ret);
    }
    if (ctc_list_pointer_empty(&(p_mcast_db->p_mem_list)))
    {
        _sys_usw_nh_mcast_entry_set_default(lchip,
                                            p_mcast_db,
                                            p_mcast_db->basic_met_offset,
                                            TRUE,
                                            TRUE);
    }
    else
    {
        sys_nh_mcast_meminfo_t* p_mem_flex = NULL;

        p_mem_flex = _ctc_container_of(ctc_list_pointer_node_tail(&(p_mcast_db->p_mem_list)),
                                       sys_nh_mcast_meminfo_t, list_head);
        /*(2) update previous member's next met offset*/
        if (CTC_FLAG_ISSET(p_mem_flex->dsmet.flag, SYS_NH_DSMET_FLAG_USE_PBM) ||
            CTC_FLAG_ISSET(p_mem_flex->dsmet.flag, SYS_NH_DSMET_FLAG_LDP_EXT_EN))
        {
            sys_met_t dsmet;
            sal_memset(&dsmet, 0, sizeof(dsmet));
            CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, p_mem_flex->dsmet.entry_type, p_mem_flex->dsmet.dsmet_offset, &dsmet));
            sal_memcpy(p_member->pbm_hw, dsmet.port_bitmap, (MCHIP_CAP(SYS_CAP_NH_MC_PBMP_NUM) >> 3));
            p_member->ldp_ext = dsmet.ldp_ext;
        }
        p_mem_flex->dsmet.next_dsmet_offset = p_mcast_db->profile_met_offset ? p_mcast_db->profile_met_offset:SYS_NH_MET_END_REPLICATE_OFFSET;
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_write_dsmet(lchip, &(p_mem_flex->dsmet), p_member));
    }

    if (stk_member_list)
    {
        if (is_add)
        {
            CTC_SET_FLAG(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_STK_MEM_PROFILE);
            if (CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE) && old_nhid)
            {
                CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, old_nhid, (sys_nh_info_com_t**)&p_mcast_profile_db));
                p_mcast_profile_db->profile_ref_cnt = (p_mcast_profile_db->profile_ref_cnt > 0) ? (p_mcast_profile_db->profile_ref_cnt - 1) : 0;
                CTC_UNSET_FLAG(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE);
            }
        }
        else
        {
            CTC_UNSET_FLAG(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_STK_MEM_PROFILE);
        }
    }
    else
    {
        if (is_add)
        {
            p_mcast_profile_db->profile_ref_cnt++;
            CTC_SET_FLAG(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE);
            CTC_UNSET_FLAG(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_STK_MEM_PROFILE);
            if (old_nhid)
            {
                CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, old_nhid, (sys_nh_info_com_t**)&p_mcast_profile_db));
                p_mcast_profile_db->profile_ref_cnt = (p_mcast_profile_db->profile_ref_cnt > 0) ? (p_mcast_profile_db->profile_ref_cnt - 1) :0;
            }
        }
        else
        {
            if (p_mcast_profile_db)
            {
                p_mcast_profile_db->profile_ref_cnt =  (p_mcast_profile_db->profile_ref_cnt > 0) ? (p_mcast_profile_db->profile_ref_cnt - 1) :0;
            }
            CTC_UNSET_FLAG(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE);
        }
    }
    return CTC_E_NONE;
}
/**
 @brief Callback function used to update bridge multicast nexthop

 @param[in] p_nh_ptr, pointer of multicast nexthop DB

 @param[in] p_para, member information

 @return CTC_E_XXX
 */
int32
sys_usw_nh_update_mcast_cb(uint8 lchip, sys_nh_info_com_t* p_nh_info,
                                 sys_nh_param_com_t* p_para /*Member info*/)
{
    sys_nh_param_mcast_t* p_nh_para_mcast = (sys_nh_param_mcast_t*)(p_para);
    sys_nh_info_mcast_t* p_mcast_db = (sys_nh_info_mcast_t*)(p_nh_info);
    uint8 member_profile = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    CTC_EQUAL_CHECK(SYS_NH_TYPE_MCAST, p_nh_info->hdr.nh_entry_type);

    /*If add dyn table, Need dsfwd ????*/
    if (p_nh_para_mcast->hdr.change_type == SYS_NH_CHANGE_TYPE_ADD_DYNTBL)
    {
        SYS_NH_DSFWD_CHK(p_nh_info->hdr.nh_entry_flags, p_para->hdr.is_dsfwd1);
        if ( !CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_MCAST_PROFILE))
        {
            CTC_ERROR_RETURN(_sys_usw_nh_mcast_add_dsfwd(lchip,  p_nh_info, 0, p_para->hdr.is_dsfwd1));
        }
        return CTC_E_NONE;
    }

    /*If no member, return*/
    if (NULL == p_nh_para_mcast->p_member)
    {
        return CTC_E_NONE;
    }
    if (((p_nh_para_mcast->p_member->member_type != SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH
        && p_nh_para_mcast->p_member->member_type != SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID) ||
        CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_MCAST_PROFILE) ||
        p_nh_para_mcast->p_member->is_mcast_aps)
        && p_nh_para_mcast->p_member->logic_rep_ability)
    {
        return CTC_E_NOT_SUPPORT;
    }
    member_profile = (p_nh_para_mcast->p_member->member_type== SYS_NH_PARAM_MCAST_MEM_REMOTE);
    /*If member have nhid, then update nh info(logic port, Hon-split) */
    if ((p_nh_para_mcast->p_member->member_type == SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE
        || p_nh_para_mcast->p_member->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH
        ||p_nh_para_mcast->p_member->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID) &&
        (p_nh_para_mcast->opcode == SYS_NH_PARAM_MCAST_ADD_MEMBER))
    {
        sys_nh_info_com_t* p_nhinfo                    = NULL;

        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip,   p_nh_para_mcast->p_member->ref_nhid, &p_nhinfo));
        if (!p_nhinfo)
        {
          return CTC_E_NOT_EXIST;
        }

        if (SYS_NH_TYPE_APS == p_nhinfo->hdr.nh_entry_type)
        {
            sys_nh_info_aps_t* p_aps_info = NULL;
            p_aps_info = (sys_nh_info_aps_t*)p_nhinfo;
            if (!DRV_FROM_AT(lchip) && (p_aps_info->arp_num == 1) && (p_nh_para_mcast->opcode == SYS_NH_PARAM_MCAST_ADD_MEMBER))
            {
                return CTC_E_INVALID_CONFIG;
            }
            p_nh_para_mcast->p_member->is_destmap_profile = p_aps_info->arp_num?1:0;
        }

        if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_MCAST_PROFILE))
        {
           member_profile = 1;
        }

        if (member_profile && p_nh_para_mcast->p_member->logic_rep_ability)
        {
            return CTC_E_NOT_SUPPORT;
        }

        if ((CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HORIZON_SPLIT_EN))
            && (0 == p_nh_para_mcast->p_member->logic_port_type_en))
        {
            p_nh_para_mcast->p_member->is_horizon_split = 1;
        }

        if( CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LOGIC_PORT))
        {
            p_nh_para_mcast->p_member->is_logic_port = 1;

            if (SYS_NH_TYPE_MPLS == p_nhinfo->hdr.nh_entry_type)
            {
                p_nh_para_mcast->p_member->logic_port = ((sys_nh_info_mpls_t*)p_nhinfo)->dest_logic_port;
            }
            else if(SYS_NH_TYPE_IP_TUNNEL == p_nhinfo->hdr.nh_entry_type)
            {
                p_nh_para_mcast->p_member->logic_port = ((sys_nh_info_ip_tunnel_t*)p_nhinfo)->dest_logic_port;
            }
            else if (SYS_NH_TYPE_BRGUC == p_nhinfo->hdr.nh_entry_type)
            {
                p_nh_para_mcast->p_member->logic_port = ((sys_nh_info_brguc_t*)p_nhinfo)->dest_logic_port;
            }
            else if (SYS_NH_TYPE_SRV6 == p_nhinfo->hdr.nh_entry_type)
            {
                p_nh_para_mcast->p_member->logic_port = ((sys_nh_info_srv6_t*)p_nhinfo)->dest_logic_port;
            }
            else if (SYS_NH_TYPE_OVERLAY == p_nhinfo->hdr.nh_entry_type)
            {
                sys_nh_info_com_t* p_vni_nhinfo                    = NULL;
                p_nh_para_mcast->p_member->logic_port = ((sys_nh_info_overlay_t*)p_nhinfo)->dest_logic_port;
                if (((sys_nh_info_overlay_t*)p_nhinfo)->nhid)
                {
                    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip,   ((sys_nh_info_overlay_t*)p_nhinfo)->nhid, &p_vni_nhinfo));
                }
                if (p_vni_nhinfo && (0 == p_nh_para_mcast->p_member->logic_port_type_en))
                {
                    p_nh_para_mcast->p_member->is_horizon_split = CTC_FLAG_ISSET(p_vni_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HORIZON_SPLIT_EN)?1:0;
                }
            }
            else if (SYS_NH_TYPE_MISC == p_nhinfo->hdr.nh_entry_type)
            {
                sys_nexthop_t dsnh;
                sal_memset(&dsnh, 0, sizeof(dsnh));
                CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)?
                SYS_NH_ENTRY_TYPE_NEXTHOP_8W : SYS_NH_ENTRY_TYPE_NEXTHOP_4W, p_nhinfo->hdr.dsnh_offset, &dsnh));
                p_nh_para_mcast->p_member->logic_port = dsnh.logic_dest_port;
            }
        }
    }
    else if(p_nh_para_mcast->p_member->member_type == SYS_NH_PARAM_BRGMC_MEM_LOCAL && (IS_MCAST_DESTMAP(p_nh_para_mcast->p_member->destid)))
    {
        CTC_ERROR_RETURN(_sys_usw_nh_check_glb_met_offset(lchip, (p_nh_para_mcast->p_member->destid&0xFFFF)<<g_usw_nh_master[lchip]->met_mode, 1 << g_usw_nh_master[lchip]->met_mode, FALSE));
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_bind_group(lchip, p_mcast_db, p_nh_para_mcast->p_member->destid&0xFFFF));
        return CTC_E_NONE;
    }

    if(member_profile || (p_mcast_db->profile_nh_id == p_nh_para_mcast->p_member->ref_nhid &&
                CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_MEM_PROFILE)))
    {
       return _sys_usw_nh_update_mcast_member_profile(lchip,p_mcast_db,p_nh_para_mcast->p_member,
                   (p_nh_para_mcast->opcode == SYS_NH_PARAM_MCAST_ADD_MEMBER));
    }

    p_nh_para_mcast->p_member->p_info_mcast = p_mcast_db;
    switch (p_nh_para_mcast->opcode)
    {
    case SYS_NH_PARAM_MCAST_ADD_MEMBER:
        {
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_add_member(lchip, p_nh_para_mcast->p_member,
                                                             &(p_mcast_db->p_mem_list),
                                                             p_mcast_db));
        }
        break;

    case SYS_NH_PARAM_MCAST_DEL_MEMBER:
        {
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_remove_member(lchip, p_nh_para_mcast->p_member,
                                                                &(p_mcast_db->p_mem_list),
                                                                p_mcast_db));
        }
        break;
    case SYS_NH_PARAM_MCAST_UPDATE_MEMBER:
            {
                CTC_ERROR_RETURN(_sys_usw_nh_mcast_update_member(lchip, p_mcast_db->basic_met_offset,
                                                                 p_nh_para_mcast->p_member,
                                                                 &(p_mcast_db->p_mem_list),
                                                                 p_mcast_db));
            }
            break;
    case SYS_NH_PARAM_MCAST_UPDATE_GRP:
        {
            CTC_ERROR_RETURN(_sys_usw_nh_mcast_update_grp(lchip, p_nh_para_mcast->p_member, p_mcast_db));
        }
        break;

    default:
        return CTC_E_INVALID_PARAM;
    }
    if (((p_nh_para_mcast->opcode == SYS_NH_PARAM_MCAST_ADD_MEMBER) || (p_nh_para_mcast->opcode == SYS_NH_PARAM_MCAST_DEL_MEMBER))
        && CTC_FLAG_ISSET(p_mcast_db->mcast_flag, SYS_NH_INFO_MCAST_FLAG_SRC_CHK_DISABLE) && (DRV_IS_TSINGMA(lchip)))
    {
        sys_nh_param_mcast_member_t mem_param;
        sal_memset(&mem_param, 0, sizeof(mem_param));
        mem_param.is_src_port_check_dis = 1;
        CTC_ERROR_RETURN(_sys_usw_nh_mcast_update_grp(lchip, &mem_param, p_mcast_db));
    }

    return CTC_E_NONE;
}

int32
sys_usw_nh_remove_mcast_all_members(uint8 lchip,  uint32 nhid)
{
    sys_nh_info_com_t*  p_nh_info = NULL;
    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, nhid, &p_nh_info));
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_INFO_MCAST, 1);
    _sys_usw_nh_remove_all_members(lchip, (sys_nh_info_mcast_t*)p_nh_info);
    return CTC_E_NONE;
}

int32
sys_usw_nh_mcast_build_member_param(uint8 lchip, ctc_mcast_nh_param_member_t* member, sys_nh_param_mcast_member_t* sys_mem_param, sys_nh_info_mcast_t* p_info_mcast)
{
    uint8 aps_brg_en               = 0;
    uint32 dest_id                 = 0;

    if ((member->member_type != CTC_NH_PARAM_MEM_BRGMC_LOCAL)
         && (member->member_type != CTC_NH_PARAM_MEM_IPMC_LOCAL)
         && member->port_bmp_en)
    {
        return CTC_E_INVALID_PARAM;
    }

    switch (member->member_type)
    {
        case CTC_NH_PARAM_MEM_BRGMC_LOCAL:
            sys_mem_param->member_type = SYS_NH_PARAM_BRGMC_MEM_LOCAL;
            sys_mem_param->is_src_port_check_dis = member->is_source_check_dis;
            if (!member->port_bmp_en)
            {
                sys_mem_param->destid = CTC_MAP_GPORT_TO_LPORT(member->destid);
                sys_mem_param->is_linkagg = CTC_IS_LINKAGG_PORT(member->destid);
                if (!sys_mem_param->is_linkagg)
                {
                   SYS_MAP_GPORT_TO_LCHIP(member->destid, lchip)
                    if (!sys_usw_chip_is_local(lchip, SYS_MAP_CTC_GPORT_TO_GCHIP(member->destid)))
                    {
                        return CTC_E_INVALID_CHIP_ID;
                    }
                }

                if (0 != member->logic_dest_port)
                {
                    sys_mem_param->logic_port = member->logic_dest_port;
                    sys_mem_param->is_logic_port = 1;
                }
            }
            break;

        case CTC_NH_PARAM_MEM_IPMC_LOCAL:
            sys_mem_param->member_type =
            member->is_vlan_port ? SYS_NH_PARAM_BRGMC_MEM_LOCAL : SYS_NH_PARAM_IPMC_MEM_LOCAL;
            sys_mem_param->l3if_type = member->l3if_type;
            sys_mem_param->vid  = member->vid;
            sys_mem_param->cvid  = member->cvid;
            sys_mem_param->is_src_port_check_dis = member->is_source_check_dis;
            if (!member->port_bmp_en)
            {
                if (CTC_FLAG_ISSET(member->flag, CTC_MCAST_NH_FLAG_LEAF_CHECK_EN))
                {
                    sys_mem_param->leaf_check_en = 1;
                }

                if (0 != member->logic_dest_port)
                {
                    sys_mem_param->logic_port = member->logic_dest_port;
                    sys_mem_param->is_logic_port = 1;
                }

                SYS_GLOBAL_PORT_CHECK(member->destid);
                sys_mem_param->destid = CTC_MAP_GPORT_TO_LPORT(member->destid);
                sys_mem_param->is_linkagg = CTC_IS_LINKAGG_PORT(member->destid);
                if (!sys_mem_param->is_linkagg)
                {
                   SYS_MAP_GPORT_TO_LCHIP(member->destid, lchip)
                    if (!sys_usw_chip_is_local(lchip, SYS_MAP_CTC_GPORT_TO_GCHIP(member->destid)))
                    {
                        return CTC_E_INVALID_CHIP_ID;
                    }
                }
            }
            break;

        case CTC_NH_PARAM_MEM_LOCAL_WITH_NH:
            {
                sys_nh_info_com_t* p_nh_com_info;
                sys_nh_info_dsnh_t  nhinfo;
                sys_mem_param->ref_nhid = member->ref_nhid;
                sys_mem_param->is_reflective = member->is_reflective;
                sys_mem_param->is_src_port_check_dis = member->is_source_check_dis;
                sys_mem_param->member_type = SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH;
                sys_mem_param->fid = member->fid;
                sys_mem_param->logic_rep_ability = CTC_FLAG_ISSET(member->flag, CTC_MCAST_NH_FLAG_LOGIC_REP_EN)?1:0;

                if (0 != member->logic_dest_port)
                {
                    sys_mem_param->logic_port = member->logic_dest_port;
                    sys_mem_param->is_logic_port = 1;
                }
                dest_id = member->destid;

                if((CTC_FLAG_ISSET(member->flag, CTC_MCAST_NH_FLAG_ASSIGN_UL_NHID)))
                {
                    sal_memset(&nhinfo, 0, sizeof(nhinfo));
                    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo(lchip, member->destid, &nhinfo, 0));
                    if(nhinfo.nh_entry_type != SYS_NH_TYPE_IPUC)
                    {
                        return CTC_E_NOT_SUPPORT;
                    }
                    dest_id = nhinfo.gport;
                    sys_mem_param->ldp_ext = nhinfo.ldp_ext;
                    sys_mem_param->member_type = SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID;
                }
                else if (CTC_FLAG_ISSET(member->flag, CTC_MCAST_NH_FLAG_ASSIGN_PORT))
                {
                    dest_id = member->destid;
                    sys_mem_param->member_type = SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID;
                }
                else
                {
                    CTC_ERROR_RETURN(sys_usw_nh_get_port(lchip, member->ref_nhid, &aps_brg_en, &dest_id));
                    sys_mem_param->member_type = aps_brg_en? SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE \
                                                                     : SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH;
                    if (aps_brg_en && (dest_id >= MCHIP_CAP(SYS_CAP_APS_GROUP_NUM)))
                    {
                        sys_mem_param->is_mcast_aps = 1;
                    }

                    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, member->ref_nhid, (sys_nh_info_com_t**)&p_nh_com_info));
                    if (p_nh_com_info->hdr.nh_entry_type == SYS_NH_TYPE_OVERLAY)
                    {
                        sys_nh_info_overlay_t* p_nh_overlay_info = (sys_nh_info_overlay_t*)p_nh_com_info;
                        sys_mem_param->is_logic_port = 1;
                        sys_mem_param->logic_port = p_nh_overlay_info->dest_logic_port;
                    }
                }

                if (CTC_FLAG_ISSET(member->flag, CTC_MCAST_NH_FLAG_LOGIC_PORT_TYPE_EN))
                {
                    sys_mem_param->is_horizon_split = member->logic_port_type;
                    sys_mem_param->logic_port_type_en = 1;
                }

                if (aps_brg_en)
                {
                    sys_mem_param->destid = dest_id;
                }
                else
                {
                    SYS_GLOBAL_PORT_CHECK(dest_id);
                    sys_mem_param->destid = CTC_MAP_GPORT_TO_LPORT(dest_id);
                }

                if (aps_brg_en || CTC_IS_LINKAGG_PORT(dest_id))
                {
                    sys_mem_param->is_linkagg  = !aps_brg_en;
                }
                else
                {
                    sys_mem_param->is_linkagg = 0;
                    if (sys_mem_param->member_type != SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH)
                    {
                        SYS_MAP_GPORT_TO_LCHIP(dest_id, lchip)
                        if (!sys_usw_chip_is_local(lchip, SYS_MAP_CTC_GPORT_TO_GCHIP(dest_id)))
                        {
                            return CTC_E_INVALID_CHIP_ID;
                        }
                    }
                }
            }
            break;

        case CTC_NH_PARAM_MEM_REMOTE:
           sys_mem_param->member_type = SYS_NH_PARAM_MCAST_MEM_REMOTE;
           sys_mem_param->destid = member->destid & 0xFFFF;/*trunk id*/
           SYS_MAP_GCHIP_TO_LCHIP(((member->destid >> 16) & 0xFF), lchip);
           break;

        default:
            return CTC_E_INVALID_PARAM;
    }

   
    if (((sys_mem_param->member_type != SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH
        && sys_mem_param->member_type != SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID) ||
        CTC_FLAG_ISSET(p_info_mcast->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_MCAST_PROFILE) ||
        sys_mem_param->is_mcast_aps)
        && sys_mem_param->logic_rep_ability)
    {
        return CTC_E_NOT_SUPPORT;
    }

    /*If member have nhid, then update nh info(logic port, Hon-split) */
    if ((sys_mem_param->member_type == SYS_NH_PARAM_BRGMC_MEM_LOCAL_WITH_APS_BRIDGE
        || sys_mem_param->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH
        ||sys_mem_param->member_type == SYS_NH_PARAM_MCAST_MEM_LOCAL_WITH_NH_DESTID))
    {
        sys_nh_info_com_t* p_nhinfo                    = NULL;

        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip,   sys_mem_param->ref_nhid, &p_nhinfo));
        if (!p_nhinfo)
        {
          return CTC_E_NOT_EXIST;
        }

        if (SYS_NH_TYPE_APS == p_nhinfo->hdr.nh_entry_type)
        {
            sys_nh_info_aps_t* p_aps_info = NULL;
            p_aps_info = (sys_nh_info_aps_t*)p_nhinfo;
            if (!DRV_FROM_AT(lchip) && (p_aps_info->arp_num == 1))
            {
                return CTC_E_INVALID_CONFIG;
            }
            sys_mem_param->is_destmap_profile = p_aps_info->arp_num?1:0;
        }
#if 0
        if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_MCAST_PROFILE))
        {
           member_profile = 1;
        }

        if (member_profile && sys_mem_param->logic_rep_ability)
        {
            return CTC_E_NOT_SUPPORT;
        }
#endif
        if ((CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HORIZON_SPLIT_EN))
            && (0 == sys_mem_param->logic_port_type_en))
        {
            sys_mem_param->is_horizon_split = 1;
        }

        if( CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LOGIC_PORT))
        {
            sys_mem_param->is_logic_port = 1;

            if (SYS_NH_TYPE_MPLS == p_nhinfo->hdr.nh_entry_type)
            {
                sys_mem_param->logic_port = ((sys_nh_info_mpls_t*)p_nhinfo)->dest_logic_port;
            }
            else if(SYS_NH_TYPE_IP_TUNNEL == p_nhinfo->hdr.nh_entry_type)
            {
                sys_mem_param->logic_port = ((sys_nh_info_ip_tunnel_t*)p_nhinfo)->dest_logic_port;
            }
            else if (SYS_NH_TYPE_BRGUC == p_nhinfo->hdr.nh_entry_type)
            {
                sys_mem_param->logic_port = ((sys_nh_info_brguc_t*)p_nhinfo)->dest_logic_port;
            }
            else if (SYS_NH_TYPE_SRV6 == p_nhinfo->hdr.nh_entry_type)
            {
                sys_mem_param->logic_port = ((sys_nh_info_srv6_t*)p_nhinfo)->dest_logic_port;
            }
            else if (SYS_NH_TYPE_OVERLAY == p_nhinfo->hdr.nh_entry_type)
            {
                sys_nh_info_com_t* p_vni_nhinfo                    = NULL;
                sys_mem_param->logic_port = ((sys_nh_info_overlay_t*)p_nhinfo)->dest_logic_port;
                if (((sys_nh_info_overlay_t*)p_nhinfo)->nhid)
                {
                    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip,   ((sys_nh_info_overlay_t*)p_nhinfo)->nhid, &p_vni_nhinfo));
                }
                if (p_vni_nhinfo && (0 == sys_mem_param->logic_port_type_en))
                {
                    sys_mem_param->is_horizon_split = CTC_FLAG_ISSET(p_vni_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HORIZON_SPLIT_EN)?1:0;
                }
            }
            else if (SYS_NH_TYPE_MISC == p_nhinfo->hdr.nh_entry_type)
            {
                sys_nexthop_t dsnh;
                sal_memset(&dsnh, 0, sizeof(dsnh));
                CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, CTC_FLAG_ISSET(p_info_mcast->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)?
                SYS_NH_ENTRY_TYPE_NEXTHOP_8W : SYS_NH_ENTRY_TYPE_NEXTHOP_4W, p_info_mcast->hdr.dsnh_offset, &dsnh));
                sys_mem_param->logic_port = dsnh.logic_dest_port;
            }
        }
    }

    return CTC_E_NONE;
}

int32
sys_usw_nh_replace_mcast_members(uint8 lchip, uint32 nhid, ctc_mcast_nh_param_member_t* mem_array, uint32 mem_num)
{
    sys_nh_info_mcast_t*  p_mcast_db = NULL; 
    ctc_list_pointer_t mem_list_new;/*new db list, sys_nh_mcast_meminfo_t*/
    ctc_list_pointer_t mem_list_old;/*new db list, sys_nh_mcast_meminfo_t*/
    ctc_list_pointer_t* p_mem_list = NULL;
    sys_nh_mcast_meminfo_param_t mem_param;
    sys_nh_mcast_meminfo_param_t* p_member = NULL;
    sys_nh_mcast_meminfo_t* p_member_info = NULL;
    ctc_list_pointer_node_t* p_pos_mem = NULL;
    ctc_list_pointer_node_t* p_pos_next = NULL;
    sys_nh_info_mcast_t mcast_db_temp;/*temp group db, include member list, sys_nh_param_mcast_member_t*/
    int32 ret = CTC_E_NONE;
    uint32 i = 0;
    uint8 idx = 0;
    uint8 pid = 0;
    uint16 lport = 0;
    uint8 stk_rsv_mem = 0;

    if (mem_num)
    {
        CTC_PTR_VALID_CHECK(mem_array);
    }
    
    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, nhid, (sys_nh_info_com_t**)(&p_mcast_db)));
    CTC_EQUAL_CHECK(SYS_NH_TYPE_MCAST, p_mcast_db->hdr.nh_entry_type);

    if (CTC_FLAG_ISSET(p_mcast_db->mcast_flag , SYS_NH_INFO_MCAST_FLAG_IS_MIRROR)
        || CTC_FLAG_ISSET(p_mcast_db->mcast_flag , SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_EN)
        || CTC_FLAG_ISSET(p_mcast_db->mcast_flag , SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_LIST_EN)
        || CTC_FLAG_ISSET(p_mcast_db->mcast_flag , SYS_NH_INFO_MCAST_FLAG_LOGIC_REP_ABILITY))
    {
        return CTC_E_INVALID_CONFIG;
    }
    sal_memcpy(&mem_list_old, &(p_mcast_db->p_mem_list), sizeof(ctc_list_pointer_t));
    
    sal_memset(&mcast_db_temp, 0, sizeof(mcast_db_temp));
    ctc_list_pointer_init(&mem_list_new);        
    ctc_list_pointer_init(&(mcast_db_temp.p_mem_list));
    mcast_db_temp.mcast_flag = p_mcast_db->mcast_flag & (SYS_NH_INFO_MCAST_FLAG_2X_GRP_ID | SYS_NH_INFO_MCAST_FLAG_4X_GRP_ID);
    sal_memcpy(&(mcast_db_temp.hdr), &(p_mcast_db->hdr), sizeof(sys_nh_info_com_hdr_t));
    mcast_db_temp.basic_met_offset = p_mcast_db->basic_met_offset;
    
    if (SYS_CB_PTR(SYS_CB_STK_GET_RSV_TRUNK_NUM))
    {
        SYS_CB(SYS_CB_STK_GET_RSV_TRUNK_NUM, lchip, &stk_rsv_mem);
    }
    
    sal_memset(&mem_param, 0, sizeof(mem_param));
    /*1. Build temp member list*/
    for (i = 0; i < mem_num; i++)
    {
        sal_memset(&mem_param, 0, sizeof(mem_param));
        /*1.1 ctc param to sys param*/
        CTC_ERROR_GOTO(sys_usw_nh_mcast_build_member_param(lchip, &(mem_array[i]), &(mem_param.member), &mcast_db_temp), ret, end);
        mem_param.member.stk_rsv_mem = stk_rsv_mem;
        mem_param.member.p_info_mcast = &mcast_db_temp;
        mem_param.member.no_hw = 1;
        /*1.2 build member list*/
        if (mem_array[i].port_bmp_en)
        {
            if (mem_array[i].gchip_id == CTC_LINKAGG_CHIPID)
            {
                mem_param.member.is_linkagg = 1;
            }
            for (idx = 0; idx < sizeof(mem_array[i].port_bmp) / 4; idx++)
            {
                if (mem_array[i].port_bmp[idx] == 0)
                {
                    continue;
                }
                for (pid = 0; pid < 32; pid++)
                {
                    if (CTC_IS_BIT_SET(mem_array[i].port_bmp[idx], pid))
                    {
                        lport = pid + idx * 32;
                        mem_param.member.destid = lport;
                        CTC_ERROR_GOTO(_sys_usw_nh_mcast_add_member(lchip, &(mem_param.member), &(mcast_db_temp.p_mem_list), &mcast_db_temp), ret, end);
                    }
                }
            }
        }
        else
        {
            CTC_ERROR_GOTO(_sys_usw_nh_mcast_add_member(lchip, &(mem_param.member), &(mcast_db_temp.p_mem_list), &mcast_db_temp), ret, end);
        }
    }
    
    /*2. Build new db list and write hw*/
    if (ctc_list_pointer_empty(&(mcast_db_temp.p_mem_list)))
    {
        _sys_usw_nh_mcast_entry_set_default(lchip, p_mcast_db,  p_mcast_db->basic_met_offset, FALSE, TRUE);
        ctc_list_pointer_init(&p_mcast_db->p_mem_list);
    }
    else
    {
        sys_nh_mcast_meminfo_param_t* p_mem_head = NULL;
        uint32 new_met_offset = SYS_NH_MET_END_REPLICATE_OFFSET;
        uint32 next_met_offset = SYS_NH_MET_END_REPLICATE_OFFSET;
        sys_nh_info_dsmet_t dsmet;
        sys_nh_param_mcast_member_t member;

        CTC_LIST_POINTER_LOOP_R(p_pos_mem, &(mcast_db_temp.p_mem_list))
        {
            p_member = _ctc_container_of(p_pos_mem, sys_nh_mcast_meminfo_param_t, list_head);
            p_member_info = mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_mcast_meminfo_t));
            if (!p_member_info)
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
                ret = CTC_E_NO_MEMORY;
                goto end;
            }

            sal_memcpy(&(p_member_info->dsmet), &(p_member->dsmet), sizeof(sys_nh_info_dsmet_t));
            new_met_offset = SYS_NH_MET_END_REPLICATE_OFFSET;
            if (0 == p_member->dsmet.dsmet_offset)
            {
                ret = (sys_usw_nh_offset_alloc(lchip, p_member_info->dsmet.entry_type, 1, &new_met_offset));
                if (ret)
                {
                    goto end;                
                }
                p_member_info->dsmet.dsmet_offset = new_met_offset;
            }

            if (0 == p_member_info->dsmet.next_dsmet_offset)
            {
                p_member_info->dsmet.next_dsmet_offset = next_met_offset;
            }
            p_member->member.no_hw = 0;
            CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip, &p_member_info->dsmet, &(p_member->member)),ret,end);
            ctc_list_pointer_insert_head(&mem_list_new, &(p_member_info->list_head));/*insert to new member db*/
            next_met_offset = new_met_offset;

            p_mem_head = _ctc_container_of(ctc_list_pointer_head(&(mcast_db_temp.p_mem_list)), sys_nh_mcast_meminfo_param_t, list_head);
            if ((p_mem_head == p_member) && (p_member->dsmet.dsmet_offset != p_mcast_db->basic_met_offset))
            {
                sal_memset(&dsmet, 0, sizeof(dsmet));
                sal_memset(&member, 0, sizeof(sys_nh_param_mcast_member_t));
                dsmet.dsmet_offset = p_mcast_db->basic_met_offset;
                dsmet.next_dsmet_offset = new_met_offset;
                dsmet.entry_type = SYS_NH_ENTRY_TYPE_MET;
                dsmet.ucastid = SYS_NH_MET_DROP_UCAST_ID;
                CTC_SET_FLAG(p_member_info->dsmet.flag, SYS_NH_DSMET_FLAG_APPEND_DROP);
                CTC_ERROR_GOTO(_sys_usw_nh_mcast_write_dsmet(lchip, &p_member_info->dsmet, &member),ret,end);
            }
        }

        p_mcast_db->physical_replication_num = mcast_db_temp.physical_replication_num;
        p_mcast_db->mcast_flag = mcast_db_temp.mcast_flag;
        sal_memcpy(&(p_mcast_db->p_mem_list), &mem_list_new, sizeof(ctc_list_pointer_t));
        mem_list_new.head.p_next->p_prev = &p_mcast_db->p_mem_list.head;
    }

end:
    /*3. Free old db list*/
    /*3.1 Free old db list*/
    if (ret == CTC_E_NONE)
    {
        if (!ctc_list_pointer_empty(&p_mcast_db->p_mem_list))
        {
            p_mcast_db->p_mem_list.head.p_next->p_prev = &mem_list_old.head;
        }
        p_mem_list = &mem_list_old;
    }
    else
    {
        p_mem_list = &mem_list_new;
    }
    CTC_LIST_POINTER_LOOP_DEL(p_pos_mem, p_pos_next, p_mem_list)
    {
        p_member_info = _ctc_container_of(p_pos_mem, sys_nh_mcast_meminfo_t, list_head);
        if (p_mcast_db->basic_met_offset != p_member_info->dsmet.dsmet_offset)
        {
            sys_usw_nh_offset_free(lchip, p_member_info->dsmet.entry_type, 1, p_member_info->dsmet.dsmet_offset);
        }    
        ctc_list_pointer_delete(p_mem_list, p_pos_mem);
        mem_free(p_member_info);
    }
    
    /*3.2 Free temp list*/
    CTC_LIST_POINTER_LOOP_DEL(p_pos_mem, p_pos_next, &(mcast_db_temp.p_mem_list))
    {
        p_member = _ctc_container_of(p_pos_mem, sys_nh_mcast_meminfo_param_t, list_head);
        ctc_list_pointer_delete(&(mcast_db_temp.p_mem_list), p_pos_mem);
        mem_free(p_member);
    }
    return ret;
}



